diff --git a/src/com/fsck/k9/mail/Address.java b/src/com/fsck/k9/mail/Address.java
index 9af0f7c6a..b40861e49 100644
--- a/src/com/fsck/k9/mail/Address.java
+++ b/src/com/fsck/k9/mail/Address.java
@@ -13,11 +13,12 @@ import com.fsck.k9.K9;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.Utility;
import org.apache.james.mime4j.codec.EncoderUtil;
-import org.apache.james.mime4j.field.address.AddressList;
-import org.apache.james.mime4j.field.address.Mailbox;
-import org.apache.james.mime4j.field.address.MailboxList;
-import org.apache.james.mime4j.field.address.NamedMailbox;
-import org.apache.james.mime4j.field.address.parser.ParseException;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.address.MailboxList;
+import org.apache.james.mime4j.field.DefaultFieldParser;
+import org.apache.james.mime4j.field.address.parser.AddressBuilder;
+import org.apache.james.mime4j.MimeException;
import java.util.ArrayList;
import java.util.List;
@@ -137,21 +138,21 @@ public class Address
}
try
{
- MailboxList parsedList = AddressList.parse(addressList).flatten();
+ MailboxList parsedList = (MailboxList) AddressBuilder.parseAddressList(addressList).flatten();
for (int i = 0, count = parsedList.size(); i < count; i++)
{
- org.apache.james.mime4j.field.address.Address address = parsedList.get(i);
- if (address instanceof NamedMailbox)
- {
- NamedMailbox namedMailbox = (NamedMailbox)address;
- addresses.add(new Address(namedMailbox.getLocalPart() + "@"
- + namedMailbox.getDomain(), namedMailbox.getName()));
- }
- else if (address instanceof Mailbox)
+ org.apache.james.mime4j.dom.address.Address address = parsedList.get(i);
+ if (address instanceof Mailbox)
{
Mailbox mailbox = (Mailbox)address;
+ if (mailbox.getName() != null )
+ {
+ addresses.add(new Address(mailbox.getLocalPart() + "@" + mailbox.getDomain(), mailbox.getName()));
+ } else
+ {
addresses.add(new Address(mailbox.getLocalPart() + "@" + mailbox.getDomain()));
}
+ }
else
{
Log.e(K9.LOG_TAG, "Unknown address type from Mime4J: "
@@ -160,7 +161,7 @@ public class Address
}
}
- catch (ParseException pe)
+ catch (MimeException pe)
{
}
return addresses.toArray(EMPTY_ADDRESS_ARRAY);
diff --git a/src/com/fsck/k9/mail/internet/DecoderUtil.java b/src/com/fsck/k9/mail/internet/DecoderUtil.java
index 22f0011dd..e1690f6f1 100644
--- a/src/com/fsck/k9/mail/internet/DecoderUtil.java
+++ b/src/com/fsck/k9/mail/internet/DecoderUtil.java
@@ -8,8 +8,8 @@ import com.fsck.k9.mail.MessagingException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import org.apache.james.mime4j.decoder.Base64InputStream;
-import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
+import org.apache.james.mime4j.codec.Base64InputStream;
+import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
import org.apache.james.mime4j.util.CharsetUtil;
diff --git a/src/com/fsck/k9/mail/internet/MimeMessage.java b/src/com/fsck/k9/mail/internet/MimeMessage.java
index 20b4a4dc7..ddabf38cc 100644
--- a/src/com/fsck/k9/mail/internet/MimeMessage.java
+++ b/src/com/fsck/k9/mail/internet/MimeMessage.java
@@ -4,12 +4,16 @@ package com.fsck.k9.mail.internet;
import com.fsck.k9.mail.*;
import com.fsck.k9.mail.store.UnavailableStorageException;
-import org.apache.james.mime4j.BodyDescriptor;
-import org.apache.james.mime4j.ContentHandler;
-import org.apache.james.mime4j.EOLConvertingInputStream;
-import org.apache.james.mime4j.MimeStreamParser;
-import org.apache.james.mime4j.field.DateTimeField;
-import org.apache.james.mime4j.field.Field;
+import org.apache.james.mime4j.stream.BodyDescriptor;
+import org.apache.james.mime4j.stream.RawField;
+import org.apache.james.mime4j.parser.ContentHandler;
+import org.apache.james.mime4j.io.EOLConvertingInputStream;
+import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.dom.field.DateTimeField;
+import org.apache.james.mime4j.dom.field.Field;
+import org.apache.james.mime4j.field.DefaultFieldParser;
+
+import org.apache.james.mime4j.MimeException;
import java.io.*;
import java.text.SimpleDateFormat;
@@ -74,7 +78,12 @@ public class MimeMessage extends Message
MimeStreamParser parser = new MimeStreamParser();
parser.setContentHandler(new MimeMessageBuilder());
- parser.parse(new EOLConvertingInputStream(in));
+ try {
+ parser.parse(new EOLConvertingInputStream(in));
+ } catch (MimeException me) {
+ throw new Error(me);
+
+ }
}
@Override
@@ -84,7 +93,7 @@ public class MimeMessage extends Message
{
try
{
- DateTimeField field = (DateTimeField)Field.parse("Date: "
+ DateTimeField field = (DateTimeField)DefaultFieldParser.parse("Date: "
+ MimeUtility.unfoldAndDecode(getFirstHeader("Date")));
mSentDate = field.getDate();
}
@@ -565,6 +574,18 @@ public class MimeMessage extends Message
expect(Part.class);
}
+ public void field(RawField field)
+ {
+ try {
+ Field parsedField = DefaultFieldParser.parse(field.getRaw(), null);
+ ((Part)stack.peek()).addHeader(parsedField.getName(), field.getBody().trim());
+ } catch (MessagingException me) {
+ throw new Error(me);
+ } catch (MimeException me) {
+ throw new Error(me);
+ }
+ }
+
public void field(String fieldData)
{
expect(Part.class);
diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java
index 72eca8f9c..1c39da32c 100644
--- a/src/com/fsck/k9/mail/internet/MimeUtility.java
+++ b/src/com/fsck/k9/mail/internet/MimeUtility.java
@@ -5,8 +5,8 @@ import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.mail.*;
import org.apache.commons.io.IOUtils;
-import org.apache.james.mime4j.decoder.Base64InputStream;
-import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
+import org.apache.james.mime4j.codec.Base64InputStream;
+import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/org/apache/james/mime4j/AbstractContentHandler.java b/src/org/apache/james/mime4j/AbstractContentHandler.java
deleted file mode 100644
index 3df6fb76b..000000000
--- a/src/org/apache/james/mime4j/AbstractContentHandler.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************
- * 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Abstract ContentHandler
with default implementations of all
- * the methods of the ContentHandler
interface.
- *
- * The default is to todo nothing.
- *
- *
- * @version $Id: AbstractContentHandler.java,v 1.3 2004/10/02 12:41:10 ntherning Exp $
- */
-public abstract class AbstractContentHandler implements ContentHandler {
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#endMultipart()
- */
- public void endMultipart() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#startMultipart(org.apache.james.mime4j.BodyDescriptor)
- */
- public void startMultipart(BodyDescriptor bd) {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream)
- */
- public void body(BodyDescriptor bd, InputStream is) throws IOException {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#endBodyPart()
- */
- public void endBodyPart() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#endHeader()
- */
- public void endHeader() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#endMessage()
- */
- public void endMessage() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#epilogue(java.io.InputStream)
- */
- public void epilogue(InputStream is) throws IOException {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#field(java.lang.String)
- */
- public void field(String fieldData) {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#preamble(java.io.InputStream)
- */
- public void preamble(InputStream is) throws IOException {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#startBodyPart()
- */
- public void startBodyPart() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#startHeader()
- */
- public void startHeader() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#startMessage()
- */
- public void startMessage() {
- }
-
- /**
- * @see org.apache.james.mime4j.ContentHandler#raw(java.io.InputStream)
- */
- public void raw(InputStream is) throws IOException {
- }
-}
diff --git a/src/org/apache/james/mime4j/CloseShieldInputStream.java b/src/org/apache/james/mime4j/CloseShieldInputStream.java
deleted file mode 100644
index 3acc98f7c..000000000
--- a/src/org/apache/james/mime4j/CloseShieldInputStream.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************
- * 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;
-
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * InputStream that shields its underlying input stream from
- * being closed.
- *
- *
- * @version $Id: CloseShieldInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $
- */
-public class CloseShieldInputStream extends InputStream {
-
- /**
- * Underlying InputStream
- */
- private InputStream is;
-
- public CloseShieldInputStream(InputStream is) {
- this.is = is;
- }
-
- public InputStream getUnderlyingStream() {
- return is;
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- checkIfClosed();
- return is.read();
- }
-
- /**
- * @see java.io.InputStream#available()
- */
- public int available() throws IOException {
- checkIfClosed();
- return is.available();
- }
-
-
- /**
- * Set the underlying InputStream to null
- */
- public void close() throws IOException {
- is = null;
- }
-
- /**
- * @see java.io.FilterInputStream#reset()
- */
- public synchronized void reset() throws IOException {
- checkIfClosed();
- is.reset();
- }
-
- /**
- * @see java.io.FilterInputStream#markSupported()
- */
- public boolean markSupported() {
- if (is == null)
- return false;
- return is.markSupported();
- }
-
- /**
- * @see java.io.FilterInputStream#mark(int)
- */
- public synchronized void mark(int readlimit) {
- if (is != null)
- is.mark(readlimit);
- }
-
- /**
- * @see java.io.FilterInputStream#skip(long)
- */
- public long skip(long n) throws IOException {
- checkIfClosed();
- return is.skip(n);
- }
-
- /**
- * @see java.io.FilterInputStream#read(byte[])
- */
- public int read(byte b[]) throws IOException {
- checkIfClosed();
- return is.read(b);
- }
-
- /**
- * @see java.io.FilterInputStream#read(byte[], int, int)
- */
- public int read(byte b[], int off, int len) throws IOException {
- checkIfClosed();
- return is.read(b, off, len);
- }
-
- /**
- * Check if the underlying InputStream is null. If so throw an Exception
- *
- * @throws IOException if the underlying InputStream is null
- */
- private void checkIfClosed() throws IOException {
- if (is == null)
- throw new IOException("Stream is closed");
- }
-}
diff --git a/src/org/apache/james/mime4j/MimeBoundaryInputStream.java b/src/org/apache/james/mime4j/MimeBoundaryInputStream.java
deleted file mode 100644
index 75d1bf7fc..000000000
--- a/src/org/apache/james/mime4j/MimeBoundaryInputStream.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/****************************************************************
- * 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-
-/**
- * Stream that constrains itself to a single MIME body part.
- * After the stream ends (i.e. read() returns -1) {@link #hasMoreParts()}
- * can be used to determine if a final boundary has been seen or not.
- * If {@link #parentEOF()} is true
an unexpected end of stream
- * has been detected in the parent stream.
- *
- *
- *
- * @version $Id: MimeBoundaryInputStream.java,v 1.2 2004/11/29 13:15:42 ntherning Exp $
- */
-public class MimeBoundaryInputStream extends InputStream {
-
- private PushbackInputStream s = null;
- private byte[] boundary = null;
- private boolean first = true;
- private boolean eof = false;
- private boolean parenteof = false;
- private boolean moreParts = true;
-
- /**
- * Creates a new MimeBoundaryInputStream.
- * @param s The underlying stream.
- * @param boundary Boundary string (not including leading hyphens).
- */
- public MimeBoundaryInputStream(InputStream s, String boundary)
- throws IOException {
-
- this.s = new PushbackInputStream(s, boundary.length() + 4);
-
- boundary = "--" + boundary;
- this.boundary = new byte[boundary.length()];
- for (int i = 0; i < this.boundary.length; i++) {
- this.boundary[i] = (byte) boundary.charAt(i);
- }
-
- /*
- * By reading one byte we will update moreParts to be as expected
- * before any bytes have been read.
- */
- int b = read();
- if (b != -1) {
- this.s.unread(b);
- }
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- public void close() throws IOException {
- s.close();
- }
-
- /**
- * Determines if the underlying stream has more parts (this stream has
- * not seen an end boundary).
- *
- * @return true
if there are more parts in the underlying
- * stream, false
otherwise.
- */
- public boolean hasMoreParts() {
- return moreParts;
- }
-
- /**
- * Determines if the parent stream has reached EOF
- *
- * @return true
if EOF has been reached for the parent stream,
- * false
otherwise.
- */
- public boolean parentEOF() {
- return parenteof;
- }
-
- /**
- * Consumes all unread bytes of this stream. After a call to this method
- * this stream will have reached EOF.
- *
- * @throws IOException on I/O errors.
- */
- public void consume() throws IOException {
- while (read() != -1) {
- }
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- if (eof) {
- return -1;
- }
-
- if (first) {
- first = false;
- if (matchBoundary()) {
- return -1;
- }
- }
-
- int b1 = s.read();
- int b2 = s.read();
-
- if (b1 == '\r' && b2 == '\n') {
- if (matchBoundary()) {
- return -1;
- }
- }
-
- if (b2 != -1) {
- s.unread(b2);
- }
-
- parenteof = b1 == -1;
- eof = parenteof;
-
- return b1;
- }
-
- private boolean matchBoundary() throws IOException {
-
- for (int i = 0; i < boundary.length; i++) {
- int b = s.read();
- if (b != boundary[i]) {
- if (b != -1) {
- s.unread(b);
- }
- for (int j = i - 1; j >= 0; j--) {
- s.unread(boundary[j]);
- }
- return false;
- }
- }
-
- /*
- * We have a match. Is it an end boundary?
- */
- int prev = s.read();
- int curr = s.read();
- moreParts = !(prev == '-' && curr == '-');
- do {
- if (curr == '\n' && prev == '\r') {
- break;
- }
- prev = curr;
- } while ((curr = s.read()) != -1);
-
- if (curr == -1) {
- moreParts = false;
- parenteof = true;
- }
-
- eof = true;
-
- return true;
- }
-}
diff --git a/src/org/apache/james/mime4j/MimeException.java b/src/org/apache/james/mime4j/MimeException.java
new file mode 100644
index 000000000..3cd928f02
--- /dev/null
+++ b/src/org/apache/james/mime4j/MimeException.java
@@ -0,0 +1,65 @@
+/****************************************************************
+ * 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;
+
+/**
+ * MIME processing exception.
+ *
+ * A MimeException
may be thrown by a {@link org.apache.james.mime4j.parser.ContentHandler} to
+ * indicate that it has failed to process a message event and that no further
+ * events should be generated.
+ *
+ * MimeException
also gets thrown by the parser to indicate MIME
+ * protocol errors, e.g. if a message boundary is too long or a header field
+ * cannot be parsed.
+ */
+public class MimeException extends Exception {
+
+ private static final long serialVersionUID = 8352821278714188542L;
+
+ /**
+ * Constructs a new MIME exception with the specified detail message.
+ *
+ * @param message detail message
+ */
+ public MimeException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a MIME exception with the specified cause.
+ *
+ * @param cause cause of the exception
+ */
+ public MimeException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a MIME exception with the specified detail message and cause.
+ *
+ * @param message detail message
+ * @param cause cause of the exception
+ */
+ public MimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/MimeIOException.java b/src/org/apache/james/mime4j/MimeIOException.java
new file mode 100644
index 000000000..5d524fc33
--- /dev/null
+++ b/src/org/apache/james/mime4j/MimeIOException.java
@@ -0,0 +1,58 @@
+/****************************************************************
+ * 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;
+
+import java.io.IOException;
+
+/**
+ * A wrapper class based on {@link IOException} for MIME protocol exceptions.
+ *
+ * This exception is used to signal a MimeException
in methods
+ * that only permit IOException
to be thrown.
+ *
+ * The cause of a MimeIOException
is always a
+ * MimeException
therefore.
+ */
+public class MimeIOException extends IOException {
+
+ private static final long serialVersionUID = 5393613459533735409L;
+
+ /**
+ * Constructs an IO exception based on {@link MimeException}.
+ *
+ * @param cause the cause.
+ */
+ public MimeIOException(MimeException cause) {
+ super(cause == null ? null : cause.getMessage());
+ initCause(cause);
+ }
+
+ /**
+ * Returns the MimeException
that caused this
+ * MimeIOException
.
+ *
+ * @return the cause of this MimeIOException
.
+ */
+ @Override
+ public MimeException getCause() {
+ return (MimeException) super.getCause();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/MimeStreamParser.java b/src/org/apache/james/mime4j/MimeStreamParser.java
deleted file mode 100644
index 5f2d09914..000000000
--- a/src/org/apache/james/mime4j/MimeStreamParser.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/****************************************************************
- * 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.BitSet;
-import java.util.LinkedList;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.james.mime4j.decoder.Base64InputStream;
-import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
-
-/**
- *
- * Parses MIME (or RFC822) message streams of bytes or characters and reports
- * parsing events to a ContentHandler
instance.
- *
- *
- * Typical usage:
- *
- * ContentHandler handler = new MyHandler();
- * MimeStreamParser parser = new MimeStreamParser();
- * parser.setContentHandler(handler);
- * parser.parse(new BufferedInputStream(new FileInputStream("mime.msg")));
- *
- * NOTE: All lines must end with CRLF
- * (\r\n
). If you are unsure of the line endings in your stream
- * you should wrap it in a {@link org.apache.james.mime4j.EOLConvertingInputStream} instance.
- *
- *
- * @version $Id: MimeStreamParser.java,v 1.8 2005/02/11 10:12:02 ntherning Exp $
- */
-public class MimeStreamParser {
- private static final Log log = LogFactory.getLog(MimeStreamParser.class);
-
- private static BitSet fieldChars = null;
-
- private RootInputStream rootStream = null;
- private LinkedList bodyDescriptors = new LinkedList();
- private ContentHandler handler = null;
- private boolean raw = false;
-
- static {
- fieldChars = new BitSet();
- for (int i = 0x21; i <= 0x39; i++) {
- fieldChars.set(i);
- }
- for (int i = 0x3b; i <= 0x7e; i++) {
- fieldChars.set(i);
- }
- }
-
- /**
- * Creates a new MimeStreamParser
instance.
- */
- public MimeStreamParser() {
- }
-
- /**
- * Parses a stream of bytes containing a MIME message.
- *
- * @param is the stream to parse.
- * @throws IOException on I/O errors.
- */
- public void parse(InputStream is) throws IOException {
- rootStream = new RootInputStream(is);
- parseMessage(rootStream);
- }
-
- /**
- * Determines if this parser is currently in raw mode.
- *
- * @return true
if in raw mode, false
- * otherwise.
- * @see #setRaw(boolean)
- */
- public boolean isRaw() {
- return raw;
- }
-
- /**
- * Enables or disables raw mode. In raw mode all future entities
- * (messages or body parts) in the stream will be reported to the
- * {@link ContentHandler#raw(InputStream)} handler method only.
- * The stream will contain the entire unparsed entity contents
- * including header fields and whatever is in the body.
- *
- * @param raw true
enables raw mode, false
- * disables it.
- */
- public void setRaw(boolean raw) {
- this.raw = raw;
- }
-
- /**
- * Finishes the parsing and stops reading lines.
- * NOTE: No more lines will be parsed but the parser
- * will still call
- * {@link ContentHandler#endMultipart()},
- * {@link ContentHandler#endBodyPart()},
- * {@link ContentHandler#endMessage()}, etc to match previous calls
- * to
- * {@link ContentHandler#startMultipart(BodyDescriptor)},
- * {@link ContentHandler#startBodyPart()},
- * {@link ContentHandler#startMessage()}, etc.
- */
- public void stop() {
- rootStream.truncate();
- }
-
- /**
- * Parses an entity which consists of a header followed by a body containing
- * arbitrary data, body parts or an embedded message.
- *
- * @param is the stream to parse.
- * @throws IOException on I/O errors.
- */
- private void parseEntity(InputStream is) throws IOException {
- BodyDescriptor bd = parseHeader(is);
-
- if (bd.isMultipart()) {
- bodyDescriptors.addFirst(bd);
-
- handler.startMultipart(bd);
-
- MimeBoundaryInputStream tempIs =
- new MimeBoundaryInputStream(is, bd.getBoundary());
- handler.preamble(new CloseShieldInputStream(tempIs));
- tempIs.consume();
-
- while (tempIs.hasMoreParts()) {
- tempIs = new MimeBoundaryInputStream(is, bd.getBoundary());
- parseBodyPart(tempIs);
- tempIs.consume();
- if (tempIs.parentEOF()) {
- if (log.isWarnEnabled()) {
- log.warn("Line " + rootStream.getLineNumber()
- + ": Body part ended prematurely. "
- + "Higher level boundary detected or "
- + "EOF reached.");
- }
- break;
- }
- }
-
- handler.epilogue(new CloseShieldInputStream(is));
-
- handler.endMultipart();
-
- bodyDescriptors.removeFirst();
-
- } else if (bd.isMessage()) {
- if (bd.isBase64Encoded()) {
- log.warn("base64 encoded message/rfc822 detected");
- is = new EOLConvertingInputStream(
- new Base64InputStream(is));
- } else if (bd.isQuotedPrintableEncoded()) {
- log.warn("quoted-printable encoded message/rfc822 detected");
- is = new EOLConvertingInputStream(
- new QuotedPrintableInputStream(is));
- }
- bodyDescriptors.addFirst(bd);
- parseMessage(is);
- bodyDescriptors.removeFirst();
- } else {
- handler.body(bd, new CloseShieldInputStream(is));
- }
-
- /*
- * Make sure the stream has been consumed.
- */
- while (is.read() != -1) {
- }
- }
-
- private void parseMessage(InputStream is) throws IOException {
- if (raw) {
- handler.raw(new CloseShieldInputStream(is));
- } else {
- handler.startMessage();
- parseEntity(is);
- handler.endMessage();
- }
- }
-
- private void parseBodyPart(InputStream is) throws IOException {
- if (raw) {
- handler.raw(new CloseShieldInputStream(is));
- } else {
- handler.startBodyPart();
- parseEntity(is);
- handler.endBodyPart();
- }
- }
-
- /**
- * Parses a header.
- *
- * @param is the stream to parse.
- * @return a BodyDescriptor
describing the body following
- * the header.
- */
- private BodyDescriptor parseHeader(InputStream is) throws IOException {
- BodyDescriptor bd = new BodyDescriptor(bodyDescriptors.isEmpty()
- ? null : (BodyDescriptor) bodyDescriptors.getFirst());
-
- handler.startHeader();
-
- int lineNumber = rootStream.getLineNumber();
-
- StringBuffer sb = new StringBuffer();
- int curr = 0;
- int prev = 0;
- while ((curr = is.read()) != -1) {
- if (curr == '\n' && (prev == '\n' || prev == 0)) {
- /*
- * [\r]\n[\r]\n or an immediate \r\n have been seen.
- */
- sb.deleteCharAt(sb.length() - 1);
- break;
- }
- sb.append((char) curr);
- prev = curr == '\r' ? prev : curr;
- }
-
- if (curr == -1 && log.isWarnEnabled()) {
- log.warn("Line " + rootStream.getLineNumber()
- + ": Unexpected end of headers detected. "
- + "Boundary detected in header or EOF reached.");
- }
-
- int start = 0;
- int pos = 0;
- int startLineNumber = lineNumber;
- while (pos < sb.length()) {
- while (pos < sb.length() && sb.charAt(pos) != '\r') {
- pos++;
- }
- if (pos < sb.length() - 1 && sb.charAt(pos + 1) != '\n') {
- pos++;
- continue;
- }
-
- if (pos >= sb.length() - 2 || fieldChars.get(sb.charAt(pos + 2))) {
-
- /*
- * field should be the complete field data excluding the
- * trailing \r\n.
- */
- String field = sb.substring(start, pos);
- start = pos + 2;
-
- /*
- * Check for a valid field.
- */
- int index = field.indexOf(':');
- boolean valid = false;
- if (index != -1 && fieldChars.get(field.charAt(0))) {
- valid = true;
- String fieldName = field.substring(0, index).trim();
- for (int i = 0; i < fieldName.length(); i++) {
- if (!fieldChars.get(fieldName.charAt(i))) {
- valid = false;
- break;
- }
- }
-
- if (valid) {
- handler.field(field);
- bd.addField(fieldName, field.substring(index + 1));
- }
- }
-
- if (!valid && log.isWarnEnabled()) {
- log.warn("Line " + startLineNumber
- + ": Ignoring invalid field: '" + field.trim() + "'");
- }
-
- startLineNumber = lineNumber;
- }
-
- pos += 2;
- lineNumber++;
- }
-
- handler.endHeader();
-
- return bd;
- }
-
- /**
- * Sets the ContentHandler
to use when reporting
- * parsing events.
- *
- * @param h the ContentHandler
.
- */
- public void setContentHandler(ContentHandler h) {
- this.handler = h;
- }
-
-}
diff --git a/src/org/apache/james/mime4j/RootInputStream.java b/src/org/apache/james/mime4j/RootInputStream.java
deleted file mode 100644
index ebf36dce2..000000000
--- a/src/org/apache/james/mime4j/RootInputStream.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************
- * 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;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * InputStream
used by the parser to wrap the original user
- * supplied stream. This stream keeps track of the current line number and
- * can also be truncated. When truncated the stream will appear to have
- * reached end of file. This is used by the parser's
- * {@link org.apache.james.mime4j.MimeStreamParser#stop()} method.
- *
- *
- * @version $Id: RootInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $
- */
-class RootInputStream extends InputStream {
- private InputStream is = null;
- private int lineNumber = 1;
- private int prev = -1;
- private boolean truncated = false;
-
- /**
- * Creates a new RootInputStream
.
- *
- * @param in the stream to read from.
- */
- public RootInputStream(InputStream is) {
- this.is = is;
- }
-
- /**
- * Gets the current line number starting at 1
- * (the number of \r\n
read so far plus 1).
- *
- * @return the current line number.
- */
- public int getLineNumber() {
- return lineNumber;
- }
-
- /**
- * Truncates this InputStream
. After this call any
- * call to {@link #read()}, {@link #read(byte[]) or
- * {@link #read(byte[], int, int)} will return
- * -1 as if end-of-file had been reached.
- */
- public void truncate() {
- this.truncated = true;
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- if (truncated) {
- return -1;
- }
-
- int b = is.read();
- if (prev == '\r' && b == '\n') {
- lineNumber++;
- }
- prev = b;
- return b;
- }
-
- /**
- *
- * @see java.io.InputStream#read(byte[], int, int)
- */
- public int read(byte[] b, int off, int len) throws IOException {
- if (truncated) {
- return -1;
- }
-
- int n = is.read(b, off, len);
- for (int i = off; i < off + n; i++) {
- if (prev == '\r' && b[i] == '\n') {
- lineNumber++;
- }
- prev = b[i];
- }
- return n;
- }
-
- /**
- * @see java.io.InputStream#read(byte[])
- */
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-}
diff --git a/src/org/apache/james/mime4j/SimpleContentHandler.java b/src/org/apache/james/mime4j/SimpleContentHandler.java
deleted file mode 100644
index 7d25d0804..000000000
--- a/src/org/apache/james/mime4j/SimpleContentHandler.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************
- * 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;
-
-import org.apache.james.mime4j.decoder.Base64InputStream;
-import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
-import org.apache.james.mime4j.field.Field;
-import org.apache.james.mime4j.message.Header;
-
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * Abstract implementation of ContentHandler that automates common
- * tasks. Currently performs header parsing and applies content-transfer
- * decoding to body parts.
- *
- *
- */
-public abstract class SimpleContentHandler extends AbstractContentHandler {
-
- /**
- * Called after headers are parsed.
- */
- public abstract void headers(Header header);
-
- /**
- * Called when the body of a discrete (non-multipart) entity is encountered.
-
- * @param bd encapsulates the values (either read from the
- * message stream or, if not present, determined implictly
- * as described in the
- * MIME rfc:s) of the Content-Type
and
- * Content-Transfer-Encoding
header fields.
- * @param is the contents of the body. Base64 or quoted-printable
- * decoding will be applied transparently.
- * @throws IOException should be thrown on I/O errors.
- */
- public abstract void bodyDecoded(BodyDescriptor bd, InputStream is) throws IOException;
-
-
- /* Implement introduced callbacks. */
-
- private Header currHeader;
-
- /**
- * @see org.apache.james.mime4j.AbstractContentHandler#startHeader()
- */
- public final void startHeader() {
- currHeader = new Header();
- }
-
- /**
- * @see org.apache.james.mime4j.AbstractContentHandler#field(java.lang.String)
- */
- public final void field(String fieldData) {
- currHeader.addField(Field.parse(fieldData));
- }
-
- /**
- * @see org.apache.james.mime4j.AbstractContentHandler#endHeader()
- */
- public final void endHeader() {
- Header tmp = currHeader;
- currHeader = null;
- headers(tmp);
- }
-
- /**
- * @see org.apache.james.mime4j.AbstractContentHandler#body(org.apache.james.mime4j.BodyDescriptor, java.io.InputStream)
- */
- public final void body(BodyDescriptor bd, InputStream is) throws IOException {
- if (bd.isBase64Encoded()) {
- bodyDecoded(bd, new Base64InputStream(is));
- }
- else if (bd.isQuotedPrintableEncoded()) {
- bodyDecoded(bd, new QuotedPrintableInputStream(is));
- }
- else {
- bodyDecoded(bd, is);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/codec/Base64InputStream.java b/src/org/apache/james/mime4j/codec/Base64InputStream.java
new file mode 100644
index 000000000..64cd31725
--- /dev/null
+++ b/src/org/apache/james/mime4j/codec/Base64InputStream.java
@@ -0,0 +1,286 @@
+/****************************************************************
+ * 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.james.mime4j.util.ByteArrayBuffer;
+
+/**
+ * Performs Base-64 decoding on an underlying stream.
+ */
+public class Base64InputStream extends InputStream {
+ private static final int ENCODED_BUFFER_SIZE = 1536;
+
+ private static final int[] BASE64_DECODE = new int[256];
+
+ static {
+ for (int i = 0; i < 256; i++)
+ BASE64_DECODE[i] = -1;
+ for (int i = 0; i < Base64OutputStream.BASE64_TABLE.length; i++)
+ BASE64_DECODE[Base64OutputStream.BASE64_TABLE[i] & 0xff] = i;
+ }
+
+ private static final byte BASE64_PAD = '=';
+
+ private static final int EOF = -1;
+
+ private final byte[] singleByte = new byte[1];
+
+ private final InputStream in;
+ private final byte[] encoded;
+ private final ByteArrayBuffer decodedBuf;
+
+ private int position = 0; // current index into encoded buffer
+ private int size = 0; // current size of encoded buffer
+
+ private boolean closed = false;
+ private boolean eof; // end of file or pad character reached
+
+ 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.monitor = monitor;
+ }
+
+ public Base64InputStream(InputStream in) {
+ this(in, false);
+ }
+
+ public Base64InputStream(InputStream in, boolean strict) {
+ this(ENCODED_BUFFER_SIZE, in, strict ? DecodeMonitor.STRICT : DecodeMonitor.SILENT);
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (closed)
+ throw new IOException("Stream has been closed");
+
+ while (true) {
+ int bytes = read0(singleByte, 0, 1);
+ if (bytes == EOF)
+ return EOF;
+
+ if (bytes == 1)
+ return singleByte[0] & 0xff;
+ }
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ if (closed)
+ throw new IOException("Stream has been closed");
+
+ if (buffer == null)
+ throw new NullPointerException();
+
+ if (buffer.length == 0)
+ return 0;
+
+ return read0(buffer, 0, buffer.length);
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int length) throws IOException {
+ if (closed)
+ throw new IOException("Stream has been closed");
+
+ if (buffer == null)
+ throw new NullPointerException();
+
+ if (offset < 0 || length < 0 || offset + length > buffer.length)
+ throw new IndexOutOfBoundsException();
+
+ if (length == 0)
+ return 0;
+
+ return read0(buffer, offset, length);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (closed)
+ return;
+
+ closed = true;
+ }
+
+ private int read0(final byte[] buffer, final int off, final int len) throws IOException {
+ int from = off;
+ int to = off + len;
+ int index = off;
+
+ // check if a previous invocation left decoded content
+ if (decodedBuf.length() > 0) {
+ int chunk = Math.min(decodedBuf.length(), len);
+ System.arraycopy(decodedBuf.buffer(), 0, buffer, index, chunk);
+ decodedBuf.remove(0, chunk);
+ index += chunk;
+ }
+
+ // eof or pad reached?
+
+ if (eof)
+ return index == from ? EOF : index - from;
+
+ // decode into given buffer
+
+ int data = 0; // holds decoded data; up to four sextets
+ int sextets = 0; // number of sextets
+
+ while (index < to) {
+ // make sure buffer not empty
+
+ while (position == size) {
+ int n = in.read(encoded, 0, encoded.length);
+ if (n == EOF) {
+ eof = true;
+
+ if (sextets != 0) {
+ // error in encoded data
+ handleUnexpectedEof(sextets);
+ }
+
+ return index == from ? EOF : index - from;
+ } else if (n > 0) {
+ position = 0;
+ size = n;
+ } else {
+ assert n == 0;
+ }
+ }
+
+ // decode buffer
+
+ while (position < size && index < to) {
+ int value = encoded[position++] & 0xff;
+
+ if (value == BASE64_PAD) {
+ index = decodePad(data, sextets, buffer, index, to);
+ return index - from;
+ }
+
+ int decoded = BASE64_DECODE[value];
+ 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++;
+
+ if (sextets == 4) {
+ sextets = 0;
+
+ byte b1 = (byte) (data >>> 16);
+ byte b2 = (byte) (data >>> 8);
+ byte b3 = (byte) data;
+
+ if (index < to - 2) {
+ buffer[index++] = b1;
+ buffer[index++] = b2;
+ buffer[index++] = b3;
+ } else {
+ if (index < to - 1) {
+ buffer[index++] = b1;
+ buffer[index++] = b2;
+ decodedBuf.append(b3);
+ } else if (index < to) {
+ buffer[index++] = b1;
+ decodedBuf.append(b2);
+ decodedBuf.append(b3);
+ } else {
+ decodedBuf.append(b1);
+ decodedBuf.append(b2);
+ decodedBuf.append(b3);
+ }
+
+ assert index == to;
+ return to - from;
+ }
+ }
+ }
+ }
+
+ assert sextets == 0;
+ assert index == to;
+ return to - from;
+ }
+
+ private int decodePad(int data, int sextets, final byte[] buffer,
+ int index, final int end) throws IOException {
+ eof = true;
+
+ if (sextets == 2) {
+ // one byte encoded as "XY=="
+
+ byte b = (byte) (data >>> 4);
+ if (index < end) {
+ buffer[index++] = b;
+ } else {
+ decodedBuf.append(b);
+ }
+ } else if (sextets == 3) {
+ // two bytes encoded as "XYZ="
+
+ byte b1 = (byte) (data >>> 10);
+ byte b2 = (byte) ((data >>> 2) & 0xFF);
+
+ if (index < end - 1) {
+ buffer[index++] = b1;
+ buffer[index++] = b2;
+ } else if (index < end) {
+ buffer[index++] = b1;
+ decodedBuf.append(b2);
+ } else {
+ decodedBuf.append(b1);
+ decodedBuf.append(b2);
+ }
+ } else {
+ // error in encoded data
+ handleUnexpecedPad(sextets);
+ }
+
+ return index;
+ }
+
+ private void handleUnexpectedEof(int sextets) throws IOException {
+ if (monitor.warn("Unexpected end of BASE64 stream", "dropping " + sextets + " sextet(s)"))
+ throw new IOException("Unexpected end of BASE64 stream");
+ }
+
+ private void handleUnexpecedPad(int sextets) throws IOException {
+ if (monitor.warn("Unexpected padding character", "dropping " + sextets + " sextet(s)"))
+ throw new IOException("Unexpected padding character");
+ }
+}
diff --git a/src/org/apache/james/mime4j/codec/Base64OutputStream.java b/src/org/apache/james/mime4j/codec/Base64OutputStream.java
new file mode 100644
index 000000000..b5bb1ca8e
--- /dev/null
+++ b/src/org/apache/james/mime4j/codec/Base64OutputStream.java
@@ -0,0 +1,321 @@
+/****************************************************************
+ * 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.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class implements section 6.8. Base64 Content-Transfer-Encoding
+ * from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies by Freed and Borenstein.
+ *
+ * Code is based on Base64 and Base64OutputStream code from Commons-Codec 1.4.
+ *
+ * @see RFC 2045
+ */
+public class Base64OutputStream extends FilterOutputStream {
+
+ // Default line length per RFC 2045 section 6.8.
+ private static final int DEFAULT_LINE_LENGTH = 76;
+
+ // CRLF line separator per RFC 2045 section 2.1.
+ private static final byte[] CRLF_SEPARATOR = { '\r', '\n' };
+
+ // This array is a lookup table that translates 6-bit positive integer index
+ // values into their "Base64 Alphabet" equivalents as specified in Table 1
+ // of RFC 2045.
+ static final byte[] BASE64_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F',
+ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+ 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', '+', '/' };
+
+ // Byte used to pad output.
+ private static final byte BASE64_PAD = '=';
+
+ // This set contains all base64 characters including the pad character. Used
+ // solely to check if a line separator contains any of these characters.
+ private static final Set BASE64_CHARS = new HashSet();
+
+ static {
+ for (byte b : BASE64_TABLE) {
+ BASE64_CHARS.add(b);
+ }
+ BASE64_CHARS.add(BASE64_PAD);
+ }
+
+ // Mask used to extract 6 bits
+ private static final int MASK_6BITS = 0x3f;
+
+ private static final int ENCODED_BUFFER_SIZE = 2048;
+
+ private final byte[] singleByte = new byte[1];
+
+ private final int lineLength;
+ private final byte[] lineSeparator;
+
+ private boolean closed = false;
+
+ private final byte[] encoded;
+ private int position = 0;
+
+ private int data = 0;
+ private int modulus = 0;
+
+ private int linePosition = 0;
+
+ /**
+ * Creates a Base64OutputStream
that writes the encoded data
+ * to the given output stream using the default line length (76) and line
+ * separator (CRLF).
+ *
+ * @param out
+ * underlying output stream.
+ */
+ public Base64OutputStream(OutputStream out) {
+ this(out, DEFAULT_LINE_LENGTH, CRLF_SEPARATOR);
+ }
+
+ /**
+ * Creates a Base64OutputStream
that writes the encoded data
+ * to the given output stream using the given line length and the default
+ * line separator (CRLF).
+ *
+ * The given line length will be rounded up to the nearest multiple of 4. If
+ * the line length is zero then the output will not be split into lines.
+ *
+ * @param out
+ * underlying output stream.
+ * @param lineLength
+ * desired line length.
+ */
+ public Base64OutputStream(OutputStream out, int lineLength) {
+ this(out, lineLength, CRLF_SEPARATOR);
+ }
+
+ /**
+ * Creates a Base64OutputStream
that writes the encoded data
+ * to the given output stream using the given line length and line
+ * separator.
+ *
+ * The given line length will be rounded up to the nearest multiple of 4. If
+ * the line length is zero then the output will not be split into lines and
+ * the line separator is ignored.
+ *
+ * The line separator must not include characters from the BASE64 alphabet
+ * (including the padding character =
).
+ *
+ * @param out
+ * underlying output stream.
+ * @param lineLength
+ * desired line length.
+ * @param lineSeparator
+ * line separator to use.
+ */
+ public Base64OutputStream(OutputStream out, int lineLength,
+ byte[] lineSeparator) {
+ super(out);
+
+ if (out == null)
+ throw new IllegalArgumentException();
+ if (lineLength < 0)
+ throw new IllegalArgumentException();
+ checkLineSeparator(lineSeparator);
+
+ this.lineLength = lineLength;
+ this.lineSeparator = new byte[lineSeparator.length];
+ System.arraycopy(lineSeparator, 0, this.lineSeparator, 0,
+ lineSeparator.length);
+
+ this.encoded = new byte[ENCODED_BUFFER_SIZE];
+ }
+
+ @Override
+ public final void write(final int b) throws IOException {
+ if (closed)
+ throw new IOException("Base64OutputStream has been closed");
+
+ singleByte[0] = (byte) b;
+ write0(singleByte, 0, 1);
+ }
+
+ @Override
+ public final void write(final byte[] buffer) throws IOException {
+ if (closed)
+ throw new IOException("Base64OutputStream has been closed");
+
+ if (buffer == null)
+ throw new NullPointerException();
+
+ if (buffer.length == 0)
+ return;
+
+ write0(buffer, 0, buffer.length);
+ }
+
+ @Override
+ public final void write(final byte[] buffer, final int offset,
+ final int length) throws IOException {
+ if (closed)
+ throw new IOException("Base64OutputStream has been closed");
+
+ if (buffer == null)
+ throw new NullPointerException();
+
+ if (offset < 0 || length < 0 || offset + length > buffer.length)
+ throw new IndexOutOfBoundsException();
+
+ if (length == 0)
+ return;
+
+ write0(buffer, offset, offset + length);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (closed)
+ throw new IOException("Base64OutputStream has been closed");
+
+ flush0();
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (closed)
+ return;
+
+ closed = true;
+ close0();
+ }
+
+ private void write0(final byte[] buffer, final int from, final int to)
+ throws IOException {
+ for (int i = from; i < to; i++) {
+ data = (data << 8) | (buffer[i] & 0xff);
+
+ if (++modulus == 3) {
+ modulus = 0;
+
+ // write line separator if necessary
+
+ if (lineLength > 0 && linePosition >= lineLength) {
+ // writeLineSeparator() inlined for performance reasons
+
+ linePosition = 0;
+
+ if (encoded.length - position < lineSeparator.length)
+ flush0();
+
+ for (byte ls : lineSeparator)
+ encoded[position++] = ls;
+ }
+
+ // encode data into 4 bytes
+
+ if (encoded.length - position < 4)
+ flush0();
+
+ encoded[position++] = BASE64_TABLE[(data >> 18) & MASK_6BITS];
+ encoded[position++] = BASE64_TABLE[(data >> 12) & MASK_6BITS];
+ encoded[position++] = BASE64_TABLE[(data >> 6) & MASK_6BITS];
+ encoded[position++] = BASE64_TABLE[data & MASK_6BITS];
+
+ linePosition += 4;
+ }
+ }
+ }
+
+ private void flush0() throws IOException {
+ if (position > 0) {
+ out.write(encoded, 0, position);
+ position = 0;
+ }
+ }
+
+ private void close0() throws IOException {
+ if (modulus != 0)
+ writePad();
+
+ // write line separator at the end of the encoded data
+
+ if (lineLength > 0 && linePosition > 0) {
+ writeLineSeparator();
+ }
+
+ flush0();
+ }
+
+ private void writePad() throws IOException {
+ // write line separator if necessary
+
+ if (lineLength > 0 && linePosition >= lineLength) {
+ writeLineSeparator();
+ }
+
+ // encode data into 4 bytes
+
+ if (encoded.length - position < 4)
+ flush0();
+
+ if (modulus == 1) {
+ encoded[position++] = BASE64_TABLE[(data >> 2) & MASK_6BITS];
+ encoded[position++] = BASE64_TABLE[(data << 4) & MASK_6BITS];
+ encoded[position++] = BASE64_PAD;
+ encoded[position++] = BASE64_PAD;
+ } else {
+ assert modulus == 2;
+ encoded[position++] = BASE64_TABLE[(data >> 10) & MASK_6BITS];
+ encoded[position++] = BASE64_TABLE[(data >> 4) & MASK_6BITS];
+ encoded[position++] = BASE64_TABLE[(data << 2) & MASK_6BITS];
+ encoded[position++] = BASE64_PAD;
+ }
+
+ linePosition += 4;
+ }
+
+ private void writeLineSeparator() throws IOException {
+ linePosition = 0;
+
+ if (encoded.length - position < lineSeparator.length)
+ flush0();
+
+ for (byte ls : lineSeparator)
+ encoded[position++] = ls;
+ }
+
+ private void checkLineSeparator(byte[] lineSeparator) {
+ if (lineSeparator.length > ENCODED_BUFFER_SIZE)
+ throw new IllegalArgumentException("line separator length exceeds "
+ + ENCODED_BUFFER_SIZE);
+
+ for (byte b : lineSeparator) {
+ if (BASE64_CHARS.contains(b)) {
+ throw new IllegalArgumentException(
+ "line separator must not contain base64 character '"
+ + (char) (b & 0xff) + "'");
+ }
+ }
+ }
+}
diff --git a/src/org/apache/james/mime4j/codec/CodecUtil.java b/src/org/apache/james/mime4j/codec/CodecUtil.java
new file mode 100644
index 000000000..b039e56db
--- /dev/null
+++ b/src/org/apache/james/mime4j/codec/CodecUtil.java
@@ -0,0 +1,108 @@
+/****************************************************************
+ * 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 java.io.OutputStream;
+
+/**
+ * Utility methods related to codecs.
+ */
+public class CodecUtil {
+
+ static final int DEFAULT_ENCODING_BUFFER_SIZE = 1024;
+
+ /**
+ * Copies the contents of one stream to the other.
+ * @param in not null
+ * @param out not null
+ * @throws IOException
+ */
+ public static void copy(final InputStream in, final OutputStream out) throws IOException {
+ final byte[] buffer = new byte[DEFAULT_ENCODING_BUFFER_SIZE];
+ int inputLength;
+ while (-1 != (inputLength = in.read(buffer))) {
+ out.write(buffer, 0, inputLength);
+ }
+ }
+
+ /**
+ * Encodes the given stream using Quoted-Printable.
+ * This assumes that stream is binary and therefore escapes
+ * all line endings.
+ * @param in not null
+ * @param out not null
+ * @throws IOException
+ */
+ public static void encodeQuotedPrintableBinary(final InputStream in, final OutputStream out) throws IOException {
+ QuotedPrintableOutputStream qpOut = new QuotedPrintableOutputStream(out, true);
+ copy(in, qpOut);
+ qpOut.close();
+ }
+
+ /**
+ * Encodes the given stream using Quoted-Printable.
+ * This assumes that stream is text and therefore does not escape
+ * all line endings.
+ * @param in not null
+ * @param out not null
+ * @throws IOException
+ */
+ public static void encodeQuotedPrintable(final InputStream in, final OutputStream out) throws IOException {
+ QuotedPrintableOutputStream qpOut = new QuotedPrintableOutputStream(out, false);
+ copy(in, qpOut);
+ qpOut.close();
+ }
+
+ /**
+ * Encodes the given stream using base64.
+ *
+ * @param in not null
+ * @param out not null
+ * @throws IOException if an I/O error occurs
+ */
+ public static void encodeBase64(final InputStream in, final OutputStream out) throws IOException {
+ Base64OutputStream b64Out = new Base64OutputStream(out);
+ copy(in, b64Out);
+ b64Out.close();
+ }
+
+ /**
+ * Wraps the given stream in a Quoted-Printable encoder.
+ * @param out not null
+ * @return encoding outputstream
+ * @throws IOException
+ */
+ public static OutputStream wrapQuotedPrintable(final OutputStream out, boolean binary) throws IOException {
+ return new QuotedPrintableOutputStream(out, binary);
+ }
+
+ /**
+ * Wraps the given stream in a Base64 encoder.
+ * @param out not null
+ * @return encoding outputstream
+ * @throws IOException
+ */
+ public static OutputStream wrapBase64(final OutputStream out) throws IOException {
+ return new Base64OutputStream(out);
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/codec/DecodeMonitor.java b/src/org/apache/james/mime4j/codec/DecodeMonitor.java
new file mode 100644
index 000000000..5f4b449ad
--- /dev/null
+++ b/src/org/apache/james/mime4j/codec/DecodeMonitor.java
@@ -0,0 +1,65 @@
+/****************************************************************
+ * 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;
+
+
+/**
+ * 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.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;
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/codec/DecoderUtil.java b/src/org/apache/james/mime4j/codec/DecoderUtil.java
new file mode 100644
index 000000000..e46863ffb
--- /dev/null
+++ b/src/org/apache/james/mime4j/codec/DecoderUtil.java
@@ -0,0 +1,260 @@
+/****************************************************************
+ * 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.james.mime4j.util.CharsetUtil;
+
+/**
+ * Static methods for decoding strings, byte arrays and encoded words.
+ */
+public class DecoderUtil {
+
+ private static final Pattern PATTERN_ENCODED_WORD = Pattern.compile(
+ "(.*?)=\\?([^\\?]+?)\\?(\\w)\\?([^\\?]+?)\\?=", Pattern.DOTALL);
+
+ /**
+ * Decodes a string containing quoted-printable encoded data.
+ *
+ * @param s the string to decode.
+ * @return the decoded bytes.
+ */
+ 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), monitor);
+
+ int b = 0;
+ while ((b = is.read()) != -1) {
+ baos.write(b);
+ }
+ } catch (IOException e) {
+ // This should never happen!
+ throw new IllegalStateException(e);
+ }
+
+ return baos.toByteArray();
+ }
+
+ /**
+ * 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, DecodeMonitor monitor) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ try {
+ byte[] bytes = s.getBytes("US-ASCII");
+
+ Base64InputStream is = new Base64InputStream(
+ new ByteArrayInputStream(bytes), monitor);
+
+ int b = 0;
+ while ((b = is.read()) != -1) {
+ baos.write(b);
+ }
+ } catch (IOException e) {
+ // This should never happen!
+ throw new IllegalStateException(e);
+ }
+
+ return baos.toByteArray();
+ }
+
+ /**
+ * Decodes an encoded text encoded with the 'B' encoding (described in
+ * RFC 2047) found in a header field body.
+ *
+ * @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, DecodeMonitor monitor)
+ throws UnsupportedEncodingException {
+ byte[] decodedBytes = decodeBase64(encodedText, monitor);
+ return new String(decodedBytes, charset);
+ }
+
+ /**
+ * Decodes an encoded text encoded with the 'Q' encoding (described in
+ * RFC 2047) found in a header field body.
+ *
+ * @param encodedText the encoded text to decode.
+ * @param charset the Java charset to use.
+ * @return the decoded string.
+ * @throws UnsupportedEncodingException if the given Java charset isn't
+ * supported.
+ */
+ static String decodeQ(String encodedText, String charset, DecodeMonitor monitor)
+ throws UnsupportedEncodingException {
+ encodedText = replaceUnderscores(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 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, DecodeMonitor monitor) throws IllegalArgumentException {
+ int tailIndex = 0;
+ boolean lastMatchValid = false;
+
+ StringBuilder sb = new StringBuilder();
+
+ for (Matcher matcher = PATTERN_ENCODED_WORD.matcher(body); matcher.find();) {
+ String separator = matcher.group(1);
+ String mimeCharset = matcher.group(2);
+ String encoding = matcher.group(3);
+ String encodedText = matcher.group(4);
+
+ String decoded = null;
+ decoded = tryDecodeEncodedWord(mimeCharset, encoding, encodedText, monitor);
+ if (decoded == null) {
+ sb.append(matcher.group(0));
+ } else {
+ if (!lastMatchValid || !CharsetUtil.isWhitespace(separator)) {
+ sb.append(separator);
+ }
+ sb.append(decoded);
+ }
+
+ tailIndex = matcher.end();
+ lastMatchValid = decoded != null;
+ }
+
+ if (tailIndex == 0) {
+ return body;
+ } else {
+ sb.append(body.substring(tailIndex));
+ return sb.toString();
+ }
+ }
+
+ // return null on error
+ private static String tryDecodeEncodedWord(final String mimeCharset,
+ final String encoding, final String encodedText, DecodeMonitor monitor) throws IllegalArgumentException {
+ String charset = CharsetUtil.toJavaCharset(mimeCharset);
+ if (charset == null) {
+ 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)) {
+ 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) {
+ 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, monitor);
+ } else if (encoding.equalsIgnoreCase("B")) {
+ return DecoderUtil.decodeB(encodedText, charset, monitor);
+ } else {
+ 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
+ monitor(monitor, mimeCharset, encoding, encodedText, "leaving word encoded",
+ "Unsupported encoding (", e.getMessage(), ") in encoded word");
+ return null;
+ } catch (RuntimeException 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 + "?=";
+ }
+
+ // Replace _ with =20
+ private static String replaceUnderscores(String str) {
+ // probably faster than String#replace(CharSequence, CharSequence)
+
+ StringBuilder sb = new StringBuilder(128);
+
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == '_') {
+ sb.append("=20");
+ } else {
+ sb.append(c);
+ }
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/org/apache/james/mime4j/codec/EncoderUtil.java b/src/org/apache/james/mime4j/codec/EncoderUtil.java
index 6841bc998..c69c77f42 100644
--- a/src/org/apache/james/mime4j/codec/EncoderUtil.java
+++ b/src/org/apache/james/mime4j/codec/EncoderUtil.java
@@ -26,31 +26,14 @@ import java.util.Locale;
import org.apache.james.mime4j.util.CharsetUtil;
-/**
- * ANDROID: THIS CLASS IS COPIED FROM A NEWER VERSION OF MIME4J
- */
-
/**
* Static methods for encoding header field values. This includes encoded-words
* as defined in RFC 2047
* or display-names of an e-mail address, for example.
- *
*/
public class EncoderUtil {
-
- // This array is a lookup table that translates 6-bit positive integer index
- // values into their "Base64 Alphabet" equivalents as specified in Table 1
- // of RFC 2045.
- // ANDROID: THIS TABLE IS COPIED FROM BASE64OUTPUTSTREAM
- static final byte[] BASE64_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F',
- 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
- 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
- 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', '+', '/' };
-
- // Byte used to pad output.
- private static final byte BASE64_PAD = '=';
+ private static final byte[] BASE64_TABLE = Base64OutputStream.BASE64_TABLE;
+ private static final char BASE64_PAD = '=';
private static final BitSet Q_REGULAR_CHARS = initChars("=_?");
@@ -374,14 +357,14 @@ public class EncoderUtil {
sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]);
- sb.append((char) BASE64_PAD);
+ sb.append(BASE64_PAD);
} else if (idx == end - 1) {
int data = (bytes[idx] & 0xff) << 16;
sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
- sb.append((char) BASE64_PAD);
- sb.append((char) BASE64_PAD);
+ sb.append(BASE64_PAD);
+ sb.append(BASE64_PAD);
}
return sb.toString();
@@ -518,14 +501,12 @@ public class EncoderUtil {
if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) {
return prefix + encodeB(bytes) + ENC_WORD_SUFFIX;
} else {
- int splitOffset = text.offsetByCodePoints(text.length() / 2, -1);
-
- String part1 = text.substring(0, splitOffset);
+ String part1 = text.substring(0, text.length() / 2);
byte[] bytes1 = encode(part1, charset);
String word1 = encodeB(prefix, part1, usedCharacters, charset,
bytes1);
- String part2 = text.substring(splitOffset);
+ String part2 = text.substring(text.length() / 2);
byte[] bytes2 = encode(part2, charset);
String word2 = encodeB(prefix, part2, 0, charset, bytes2);
@@ -546,14 +527,12 @@ public class EncoderUtil {
if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) {
return prefix + encodeQ(bytes, usage) + ENC_WORD_SUFFIX;
} else {
- int splitOffset = text.offsetByCodePoints(text.length() / 2, -1);
-
- String part1 = text.substring(0, splitOffset);
+ String part1 = text.substring(0, text.length() / 2);
byte[] bytes1 = encode(part1, charset);
String word1 = encodeQ(prefix, part1, usage, usedCharacters,
charset, bytes1);
- String part2 = text.substring(splitOffset);
+ String part2 = text.substring(text.length() / 2);
byte[] bytes2 = encode(part2, charset);
String word2 = encodeQ(prefix, part2, usage, 0, charset, bytes2);
diff --git a/src/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java b/src/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
deleted file mode 100644
index ea1c68c05..000000000
--- a/src/org/apache/james/mime4j/codec/QuotedPrintableEncoder.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/****************************************************************
- * 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 java.io.OutputStream;
-
-// Taken from Apache Mime4j 0.6
-
-final class QuotedPrintableEncoder
-{
- private static final byte TAB = 0x09;
- private static final byte SPACE = 0x20;
- private static final byte EQUALS = 0x3D;
- private static final byte CR = 0x0D;
- private static final byte LF = 0x0A;
- private static final byte QUOTED_PRINTABLE_LAST_PLAIN = 0x7E;
- private static final int QUOTED_PRINTABLE_MAX_LINE_LENGTH = 76;
- private static final int QUOTED_PRINTABLE_OCTETS_PER_ESCAPE = 3;
- private static final byte[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
-
- private final byte[] inBuffer;
- private final byte[] outBuffer;
- private final boolean binary;
-
- private boolean pendingSpace;
- private boolean pendingTab;
- private boolean pendingCR;
- private int nextSoftBreak;
- private int outputIndex;
- private OutputStream out;
-
- public QuotedPrintableEncoder(int bufferSize, boolean binary)
- {
- inBuffer = new byte[bufferSize];
- outBuffer = new byte[3 * bufferSize];
- outputIndex = 0;
- nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
- out = null;
- this.binary = binary;
- pendingSpace = false;
- pendingTab = false;
- pendingCR = false;
- }
-
- void initEncoding(final OutputStream out)
- {
- this.out = out;
- pendingSpace = false;
- pendingTab = false;
- pendingCR = false;
- nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
- }
-
- void encodeChunk(byte[] buffer, int off, int len) throws IOException
- {
- for (int inputIndex = off; inputIndex < len + off; inputIndex++)
- {
- encode(buffer[inputIndex]);
- }
- }
-
- void completeEncoding() throws IOException
- {
- writePending();
- flushOutput();
- }
-
- public void encode(final InputStream in, final OutputStream out)
- throws IOException
- {
- initEncoding(out);
- int inputLength;
- while ((inputLength = in.read(inBuffer)) > -1)
- {
- encodeChunk(inBuffer, 0, inputLength);
- }
- completeEncoding();
- }
-
- private void writePending() throws IOException
- {
- if (pendingSpace)
- {
- plain(SPACE);
- }
- else if (pendingTab)
- {
- plain(TAB);
- }
- else if (pendingCR)
- {
- plain(CR);
- }
- clearPending();
- }
-
- private void clearPending() throws IOException
- {
- pendingSpace = false;
- pendingTab = false;
- pendingCR = false;
- }
-
- private void encode(byte next) throws IOException
- {
- if (next == LF)
- {
- if (binary)
- {
- writePending();
- escape(next);
- }
- else
- {
- if (pendingCR)
- {
- // Expect either space or tab pending
- // but not both
- if (pendingSpace)
- {
- escape(SPACE);
- }
- else if (pendingTab)
- {
- escape(TAB);
- }
- lineBreak();
- clearPending();
- }
- else
- {
- writePending();
- plain(next);
- }
- }
- }
- else if (next == CR)
- {
- if (binary)
- {
- escape(next);
- }
- else
- {
- pendingCR = true;
- }
- }
- else
- {
- writePending();
- if (next == SPACE)
- {
- if (binary)
- {
- escape(next);
- }
- else
- {
- pendingSpace = true;
- }
- }
- else if (next == TAB)
- {
- if (binary)
- {
- escape(next);
- }
- else
- {
- pendingTab = true;
- }
- }
- else if (next < SPACE)
- {
- escape(next);
- }
- else if (next > QUOTED_PRINTABLE_LAST_PLAIN)
- {
- escape(next);
- }
- else if (next == EQUALS)
- {
- escape(next);
- }
- else
- {
- plain(next);
- }
- }
- }
-
- private void plain(byte next) throws IOException
- {
- if (--nextSoftBreak <= 1)
- {
- softBreak();
- }
- write(next);
- }
-
- private void escape(byte next) throws IOException
- {
- if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE)
- {
- softBreak();
- }
-
- int nextUnsigned = next & 0xff;
-
- write(EQUALS);
- --nextSoftBreak;
- write(HEX_DIGITS[nextUnsigned >> 4]);
- --nextSoftBreak;
- write(HEX_DIGITS[nextUnsigned % 0x10]);
- }
-
- private void write(byte next) throws IOException
- {
- outBuffer[outputIndex++] = next;
- if (outputIndex >= outBuffer.length)
- {
- flushOutput();
- }
- }
-
- private void softBreak() throws IOException
- {
- write(EQUALS);
- lineBreak();
- }
-
- private void lineBreak() throws IOException
- {
- write(CR);
- write(LF);
- nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
- }
-
- void flushOutput() throws IOException
- {
- if (outputIndex < outBuffer.length)
- {
- out.write(outBuffer, 0, outputIndex);
- }
- else
- {
- out.write(outBuffer);
- }
- outputIndex = 0;
- }
-}
diff --git a/src/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java b/src/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
new file mode 100644
index 000000000..7d07bde86
--- /dev/null
+++ b/src/org/apache/james/mime4j/codec/QuotedPrintableInputStream.java
@@ -0,0 +1,309 @@
+/****************************************************************
+ * 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.james.mime4j.util.ByteArrayBuffer;
+
+/**
+ * Performs Quoted-Printable decoding on an underlying stream.
+ */
+public class QuotedPrintableInputStream extends InputStream {
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 2;
+
+ private static final byte EQ = 0x3D;
+ private static final byte CR = 0x0D;
+ private static final byte LF = 0x0A;
+
+ private final byte[] singleByte = new byte[1];
+
+ private final InputStream in;
+ private final ByteArrayBuffer decodedBuf;
+ private final ByteArrayBuffer blanks;
+
+ private final byte[] encoded;
+ private int pos = 0; // current index into encoded buffer
+ private int limit = 0; // current size of encoded buffer
+
+ private boolean closed;
+
+ 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.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(in, false);
+ }
+
+ /**
+ * 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 {
+ closed = true;
+ }
+
+ private int fillBuffer() throws IOException {
+ // Compact buffer if needed
+ if (pos < limit) {
+ System.arraycopy(encoded, pos, encoded, 0, limit - pos);
+ limit -= pos;
+ pos = 0;
+ } else {
+ limit = 0;
+ pos = 0;
+ }
+
+ int capacity = encoded.length - limit;
+ if (capacity > 0) {
+ int bytesRead = in.read(encoded, limit, capacity);
+ if (bytesRead > 0) {
+ limit += bytesRead;
+ }
+ return bytesRead;
+ } else {
+ return 0;
+ }
+ }
+
+ private int getnext() {
+ if (pos < limit) {
+ byte b = encoded[pos];
+ pos++;
+ return b & 0xFF;
+ } else {
+ return -1;
+ }
+ }
+
+ private int peek(int i) {
+ if (pos + i < limit) {
+ return encoded[pos + i] & 0xFF;
+ } else {
+ return -1;
+ }
+ }
+
+ private int transfer(
+ 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);
+ System.arraycopy(blanks.buffer(), 0, buffer, index, chunk);
+ index += chunk;
+ int remaining = blanks.length() - chunk;
+ if (remaining > 0) {
+ 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) {
+ buffer[index++] = (byte) b;
+ } else {
+ decodedBuf.append(b);
+ }
+ }
+ return index;
+ }
+
+ private int read0(final byte[] buffer, final int off, final int len) throws IOException {
+ boolean eof = false;
+ int from = off;
+ int to = off + len;
+ int index = off;
+
+ // check if a previous invocation left decoded content
+ if (decodedBuf.length() > 0) {
+ int chunk = Math.min(decodedBuf.length(), to - index);
+ System.arraycopy(decodedBuf.buffer(), 0, buffer, index, chunk);
+ decodedBuf.remove(0, chunk);
+ index += chunk;
+ }
+
+ while (index < to) {
+
+ if (limit - pos < 3) {
+ int bytesRead = fillBuffer();
+ eof = bytesRead == -1;
+ }
+
+ // end of stream?
+ if (limit - pos == 0 && eof) {
+ 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) {
+ // hard line break
+ index = transfer(CR, buffer, index, to, false);
+ index = transfer(LF, buffer, index, to, false);
+ }
+ }
+ blanks.clear();
+ } else if (b == EQ) {
+ if (limit - pos < 2 && !eof) {
+ // not enough buffered data
+ pos--;
+ break;
+ }
+
+ // found special char '='
+ int b2 = getnext();
+ if (b2 == EQ) {
+ index = transfer(b2, buffer, index, to, true);
+ // deal with '==\r\n' brokenness
+ 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
+ index = transfer(-1, buffer, index, to, true);
+ if (b2 != LF) {
+ blanks.append(b);
+ blanks.append(b2);
+ }
+ } else {
+ int b3 = getnext();
+ int upper = convert(b2);
+ int lower = convert(b3);
+ if (upper < 0 || lower < 0) {
+ 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);
+ }
+ }
+ } else if (Character.isWhitespace(b)) {
+ blanks.append(b);
+ } else {
+ index = transfer((int) b & 0xFF, buffer, index, to, true);
+ }
+ }
+ }
+ return to - from;
+ }
+
+ /**
+ * Converts '0' => 0, 'A' => 10, etc.
+ * @param c ASCII character value.
+ * @return Numeric value of hexadecimal character.
+ */
+ private int convert(int c) {
+ if (c >= '0' && c <= '9') {
+ return (c - '0');
+ } else if (c >= 'A' && c <= 'F') {
+ return (0xA + (c - 'A'));
+ } else if (c >= 'a' && c <= 'f') {
+ return (0xA + (c - 'a'));
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (closed) {
+ throw new IOException("Stream has been closed");
+ }
+ for (;;) {
+ int bytes = read(singleByte, 0, 1);
+ if (bytes == -1) {
+ return -1;
+ }
+ if (bytes == 1) {
+ return singleByte[0] & 0xff;
+ }
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (closed) {
+ throw new IOException("Stream has been closed");
+ }
+ return read0(b, off, len);
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java b/src/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
index ba5f36332..4ce8356f8 100644
--- a/src/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
+++ b/src/org/apache/james/mime4j/codec/QuotedPrintableOutputStream.java
@@ -23,66 +23,211 @@ import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-// Taken from Apache Mime4j 0.6
-
/**
* Performs Quoted-Printable encoding on an underlying stream.
*/
-public class QuotedPrintableOutputStream extends FilterOutputStream
-{
+public class QuotedPrintableOutputStream extends FilterOutputStream {
- private static final int DEFAULT_ENCODING_BUFFER_SIZE = 1024;
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 3;
+
+ private static final byte TB = 0x09;
+ private static final byte SP = 0x20;
+ private static final byte EQ = 0x3D;
+ private static final byte CR = 0x0D;
+ private static final byte LF = 0x0A;
+ private static final byte QUOTED_PRINTABLE_LAST_PLAIN = 0x7E;
+ private static final int QUOTED_PRINTABLE_MAX_LINE_LENGTH = 76;
+ private static final int QUOTED_PRINTABLE_OCTETS_PER_ESCAPE = 3;
+ private static final byte[] HEX_DIGITS = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+ private final byte[] outBuffer;
+ private final boolean binary;
+
+ private boolean pendingSpace;
+ private boolean pendingTab;
+ private boolean pendingCR;
+ private int nextSoftBreak;
+ private int outputIndex;
- private QuotedPrintableEncoder encoder;
private boolean closed = false;
- public QuotedPrintableOutputStream(OutputStream out, boolean binary)
- {
+ private byte[] singleByte = new byte[1];
+
+ public QuotedPrintableOutputStream(int bufsize, OutputStream out, boolean binary) {
super(out);
- encoder = new QuotedPrintableEncoder(DEFAULT_ENCODING_BUFFER_SIZE, binary);
- encoder.initEncoding(out);
+ this.outBuffer = new byte[bufsize];
+ this.binary = binary;
+ this.pendingSpace = false;
+ this.pendingTab = false;
+ this.pendingCR = false;
+ this.outputIndex = 0;
+ this.nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH + 1;
+ }
+
+ public QuotedPrintableOutputStream(OutputStream out, boolean binary) {
+ this(DEFAULT_BUFFER_SIZE, out, binary);
+ }
+
+ private void encodeChunk(byte[] buffer, int off, int len) throws IOException {
+ for (int inputIndex = off; inputIndex < len + off; inputIndex++) {
+ encode(buffer[inputIndex]);
+ }
+ }
+
+ private void completeEncoding() throws IOException {
+ writePending();
+ flushOutput();
+ }
+
+ private void writePending() throws IOException {
+ if (pendingSpace) {
+ plain(SP);
+ } else if (pendingTab) {
+ plain(TB);
+ } else if (pendingCR) {
+ plain(CR);
+ }
+ clearPending();
+ }
+
+ private void clearPending() throws IOException {
+ pendingSpace = false;
+ pendingTab = false;
+ pendingCR = false;
+ }
+
+ private void encode(byte next) throws IOException {
+ if (next == LF) {
+ if (binary) {
+ writePending();
+ escape(next);
+ } else {
+ if (pendingCR) {
+ // Expect either space or tab pending
+ // but not both
+ if (pendingSpace) {
+ escape(SP);
+ } else if (pendingTab) {
+ escape(TB);
+ }
+ lineBreak();
+ clearPending();
+ } else {
+ writePending();
+ plain(next);
+ }
+ }
+ } else if (next == CR) {
+ if (binary) {
+ escape(next);
+ } else {
+ pendingCR = true;
+ }
+ } else {
+ writePending();
+ if (next == SP) {
+ if (binary) {
+ escape(next);
+ } else {
+ pendingSpace = true;
+ }
+ } else if (next == TB) {
+ if (binary) {
+ escape(next);
+ } else {
+ pendingTab = true;
+ }
+ } else if (next < SP) {
+ escape(next);
+ } else if (next > QUOTED_PRINTABLE_LAST_PLAIN) {
+ escape(next);
+ } else if (next == EQ) {
+ escape(next);
+ } else {
+ plain(next);
+ }
+ }
+ }
+
+ private void plain(byte next) throws IOException {
+ if (--nextSoftBreak <= 1) {
+ softBreak();
+ }
+ write(next);
+ }
+
+ private void escape(byte next) throws IOException {
+ if (--nextSoftBreak <= QUOTED_PRINTABLE_OCTETS_PER_ESCAPE) {
+ softBreak();
+ }
+
+ int nextUnsigned = next & 0xff;
+
+ write(EQ);
+ --nextSoftBreak;
+ write(HEX_DIGITS[nextUnsigned >> 4]);
+ --nextSoftBreak;
+ write(HEX_DIGITS[nextUnsigned % 0x10]);
+ }
+
+ private void write(byte next) throws IOException {
+ outBuffer[outputIndex++] = next;
+ if (outputIndex >= outBuffer.length) {
+ flushOutput();
+ }
+ }
+
+ private void softBreak() throws IOException {
+ write(EQ);
+ lineBreak();
+ }
+
+ private void lineBreak() throws IOException {
+ write(CR);
+ write(LF);
+ nextSoftBreak = QUOTED_PRINTABLE_MAX_LINE_LENGTH;
+ }
+
+ void flushOutput() throws IOException {
+ if (outputIndex < outBuffer.length) {
+ out.write(outBuffer, 0, outputIndex);
+ } else {
+ out.write(outBuffer);
+ }
+ outputIndex = 0;
}
@Override
- public void close() throws IOException
- {
+ public void close() throws IOException {
if (closed)
- {
return;
- }
- try
- {
- encoder.completeEncoding();
+ try {
+ completeEncoding();
// do not close the wrapped stream
- }
- finally
- {
+ } finally {
closed = true;
}
}
@Override
- public void flush() throws IOException
- {
- encoder.flushOutput();
+ public void flush() throws IOException {
+ flushOutput();
}
@Override
- public void write(int b) throws IOException
- {
- this.write(new byte[] { (byte) b }, 0, 1);
+ public void write(int b) throws IOException {
+ singleByte[0] = (byte) b;
+ this.write(singleByte, 0, 1);
}
@Override
- public void write(byte[] b, int off, int len) throws IOException
- {
- if (closed)
- {
- throw new IOException("QuotedPrintableOutputStream has been closed");
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (closed) {
+ throw new IOException("Stream has been closed");
}
-
- encoder.encodeChunk(b, off, len);
+ encodeChunk(b, off, len);
}
-}
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/decoder/Base64InputStream.java b/src/org/apache/james/mime4j/decoder/Base64InputStream.java
deleted file mode 100644
index 9af54951b..000000000
--- a/src/org/apache/james/mime4j/decoder/Base64InputStream.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/****************************************************************
- * 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.decoder;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Performs Base-64 decoding on an underlying stream.
- *
- *
- * @version $Id: Base64InputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $
- */
-public class Base64InputStream extends InputStream {
- private static Log log = LogFactory.getLog(Base64InputStream.class);
-
- private final InputStream s;
- private final ByteQueue byteq = new ByteQueue(3);
- private boolean done = false;
-
- public Base64InputStream(InputStream s) {
- this.s = s;
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- public void close() throws IOException {
- s.close();
- }
-
- public int read() throws IOException {
- if (byteq.count() == 0) {
- fillBuffer();
- if (byteq.count() == 0) {
- return -1;
- }
- }
-
- byte val = byteq.dequeue();
- if (val >= 0)
- return val;
- else
- return val & 0xFF;
- }
-
- /**
- * Retrieve data from the underlying stream, decode it,
- * and put the results in the byteq.
- * @throws IOException
- */
- private void fillBuffer() throws IOException {
- byte[] data = new byte[4];
- int pos = 0;
-
- int i;
- while (!done) {
- switch (i = s.read()) {
- case -1:
- if (pos > 0) {
- log.warn("Unexpected EOF in MIME parser, dropping "
- + pos + " sextets");
- }
- return;
- case '=':
- decodeAndEnqueue(data, pos);
- done = true;
- break;
- default:
- byte sX = TRANSLATION[i];
- if (sX < 0)
- continue;
- data[pos++] = sX;
- if (pos == data.length) {
- decodeAndEnqueue(data, pos);
- return;
- }
- break;
- }
- }
- }
-
- private void decodeAndEnqueue(byte[] data, int len) {
- int accum = 0;
- accum |= data[0] << 18;
- accum |= data[1] << 12;
- accum |= data[2] << 6;
- accum |= data[3];
-
- byte b1 = (byte)(accum >>> 16);
- byteq.enqueue(b1);
-
- if (len > 2) {
- byte b2 = (byte)((accum >>> 8) & 0xFF);
- byteq.enqueue(b2);
-
- if (len > 3) {
- byte b3 = (byte)(accum & 0xFF);
- byteq.enqueue(b3);
- }
- }
- }
-
- private static byte[] TRANSLATION = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xF0 */
- };
-
-
-}
diff --git a/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/src/org/apache/james/mime4j/decoder/DecoderUtil.java
deleted file mode 100644
index c39129367..000000000
--- a/src/org/apache/james/mime4j/decoder/DecoderUtil.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/****************************************************************
- * 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.decoder;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.james.mime4j.util.CharsetUtil;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Static methods for decoding strings, byte arrays and encoded words.
- *
- *
- * @version $Id: DecoderUtil.java,v 1.3 2005/02/07 15:33:59 ntherning Exp $
- */
-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
- */
- StringBuffer sb = new StringBuffer();
- 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.
- *
- * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J
- *
- * @param body the string to decode.
- * @return the decoded string.
- */
- public static String decodeEncodedWords(String body) {
-
- // ANDROID: Most strings will not include "=?" so a quick test can prevent unneeded
- // object creation. This could also be handled via lazy creation of the StringBuilder.
- if (body.indexOf("=?") == -1) {
- return body;
- }
-
- int previousEnd = 0;
- boolean previousWasEncoded = false;
-
- StringBuilder sb = new StringBuilder();
-
- while (true) {
- int begin = body.indexOf("=?", previousEnd);
-
- // ANDROID: The mime4j original version has an error here. It gets confused if
- // the encoded string begins with an '=' (just after "?Q?"). This patch seeks forward
- // to find the two '?' in the "header", before looking for the final "?=".
- int endScan = begin + 2;
- if (begin != -1) {
- int qm1 = body.indexOf('?', endScan + 2);
- int qm2 = body.indexOf('?', qm1 + 1);
- if (qm2 != -1) {
- endScan = qm2 + 1;
- }
- }
-
- int end = begin == -1 ? -1 : body.indexOf("?=", endScan);
- 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;
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java b/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java
deleted file mode 100644
index 3a3a1a451..000000000
--- a/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************
- * 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.decoder;
-
-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.
- *
- *
- *
- * @version $Id: QuotedPrintableInputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $
- */
-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;
-
- public QuotedPrintableInputStream(InputStream stream) {
- this.stream = stream;
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- public void close() throws IOException {
- stream.close();
- }
-
- public int read() throws IOException {
- 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 = (byte)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 = so far; expecting another 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");
- }
- }
-
-}
diff --git a/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java b/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java
deleted file mode 100644
index f01194fd1..000000000
--- a/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/****************************************************************
- * 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.decoder;
-
-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.
- *
- * The removal order of an UnboundedFifoByteBuffer
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.
- *
- * 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.
- *
- * Note that this implementation is not synchronized. The following can be
- * used to provide synchronized access to your UnboundedFifoByteBuffer
:
- *
- * Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer());
- *
- *
- * This buffer prevents null objects from being added.
- *
- * @since Commons Collections 3.0 (previously in main package v2.1)
- * @version $Revision: 1.1 $ $Date: 2004/08/24 06:52:02 $
- *
- *
- *
- *
- *
- *
- */
-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:
- *
- *
- * new UnboundedFifoByteBuffer(32);
- *
- */
- 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 iterator() {
- return new Iterator() {
-
- private int index = head;
- private int lastReturnedIndex = -1;
-
- public boolean hasNext() {
- return index != tail;
-
- }
-
- public Object 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
diff --git a/src/org/apache/james/mime4j/dom/BinaryBody.java b/src/org/apache/james/mime4j/dom/BinaryBody.java
new file mode 100644
index 000000000..d9d20a4e2
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/BinaryBody.java
@@ -0,0 +1,33 @@
+/****************************************************************
+ * 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.dom;
+
+/**
+ * A body containing binary data.
+ */
+public abstract class BinaryBody extends SingleBody {
+
+ /**
+ * Sole constructor.
+ */
+ protected BinaryBody() {
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/message/Body.java b/src/org/apache/james/mime4j/dom/Body.java
similarity index 74%
rename from src/org/apache/james/mime4j/message/Body.java
rename to src/org/apache/james/mime4j/dom/Body.java
index 5d9b38190..d1482830a 100644
--- a/src/org/apache/james/mime4j/message/Body.java
+++ b/src/org/apache/james/mime4j/dom/Body.java
@@ -17,38 +17,30 @@
* under the License. *
****************************************************************/
-package org.apache.james.mime4j.message;
-
-import java.io.IOException;
-import java.io.OutputStream;
+package org.apache.james.mime4j.dom;
/**
* Encapsulates the body of an entity (see RFC 2045).
- *
- *
- * @version $Id: Body.java,v 1.4 2004/10/04 15:36:43 ntherning Exp $
+ *
+ * A body can be a {@link Message}, a {@link Multipart} or a {@link SingleBody}.
+ * This interface should not be implemented directly by classes other than
+ * those.
*/
-public interface Body {
+public interface Body extends Disposable {
/**
* Gets the parent of this body.
- *
+ *
* @return the parent.
*/
Entity getParent();
-
+
/**
* Sets the parent of this body.
- *
- * @param parent the parent.
+ *
+ * @param parent
+ * the parent.
*/
void setParent(Entity parent);
-
- /**
- * Writes this body to the given stream in MIME message format.
- *
- * @param out the stream to write to.
- * @throws IOException on I/O errors.
- */
- void writeTo(OutputStream out) throws IOException;
+
}
diff --git a/src/org/apache/james/mime4j/dom/Disposable.java b/src/org/apache/james/mime4j/dom/Disposable.java
new file mode 100644
index 000000000..5254f00fd
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/Disposable.java
@@ -0,0 +1,36 @@
+/****************************************************************
+ * 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.dom;
+
+/**
+ * A Disposable is an object that should be disposed of explicitly
+ * when it is no longer needed.
+ *
+ * The dispose method is invoked to release resources that the object is
+ * holding (such as open files).
+ */
+public interface Disposable {
+ /**
+ * Free any resources this object is holding and prepares this object
+ * for garbage collection. Once an object has been disposed of it can no
+ * longer be used.
+ */
+ void dispose();
+}
diff --git a/src/org/apache/james/mime4j/dom/Entity.java b/src/org/apache/james/mime4j/dom/Entity.java
new file mode 100644
index 000000000..92fe16562
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/Entity.java
@@ -0,0 +1,550 @@
+/****************************************************************
+ * 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.dom;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.james.mime4j.dom.field.ContentDispositionField;
+import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
+import org.apache.james.mime4j.dom.field.ContentTypeField;
+import org.apache.james.mime4j.dom.field.Field;
+import org.apache.james.mime4j.dom.field.FieldName;
+
+/**
+ * MIME entity. An entity has a header and a body (see RFC 2045).
+ */
+public abstract class Entity implements Disposable {
+ private Header header = null;
+ private Body body = null;
+ private Entity parent = null;
+
+ /**
+ * Creates a new Entity
. Typically invoked implicitly by a
+ * subclass constructor.
+ */
+ protected Entity() {
+ }
+
+ /**
+ * Gets the parent entity of this entity.
+ * Returns null
if this is the root entity.
+ *
+ * @return the parent or null
.
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * Sets the parent entity of this entity.
+ *
+ * @param parent the parent entity or null
if
+ * this will be the root entity.
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the entity header.
+ *
+ * @return the header.
+ */
+ public Header getHeader() {
+ return header;
+ }
+
+ /**
+ * Sets the entity header.
+ *
+ * @param header the header.
+ */
+ public void setHeader(Header header) {
+ this.header = header;
+ }
+
+ /**
+ * Gets the body of this entity.
+ *
+ * @return the body,
+ */
+ public Body getBody() {
+ return body;
+ }
+
+ /**
+ * Sets the body of this entity.
+ *
+ * @param body the body.
+ * @throws IllegalStateException if the body has already been set.
+ */
+ public void setBody(Body body) {
+ if (this.body != null)
+ throw new IllegalStateException("body already set");
+
+ this.body = body;
+ body.setParent(this);
+ }
+
+ /**
+ * Removes and returns the body of this entity. The removed body may be
+ * attached to another entity. If it is no longer needed it should be
+ * {@link Disposable#dispose() disposed} of.
+ *
+ * @return the removed body or null
if no body was set.
+ */
+ public Body removeBody() {
+ if (body == null)
+ return null;
+
+ Body body = this.body;
+ this.body = null;
+ body.setParent(null);
+
+ return body;
+ }
+
+ /**
+ * Sets the specified message as body of this entity and the content type to
+ * "message/rfc822". A Header
is created if this
+ * entity does not already have one.
+ *
+ * @param message
+ * the message to set as body.
+ */
+ public void setMessage(Message message) {
+ setBody(message, "message/rfc822", null);
+ }
+
+ /**
+ * Sets the specified multipart as body of this entity. Also sets the
+ * content type accordingly and creates a message boundary string. A
+ * Header
is created if this entity does not already have
+ * one.
+ *
+ * @param multipart
+ * the multipart to set as body.
+ */
+ public void setMultipart(Multipart multipart) {
+ String mimeType = "multipart/" + multipart.getSubType();
+ Map parameters = Collections.singletonMap("boundary",
+ newUniqueBoundary());
+
+ setBody(multipart, mimeType, parameters);
+ }
+
+ /**
+ * Sets the specified multipart as body of this entity. Also sets the
+ * content type accordingly and creates a message boundary string. A
+ * Header
is created if this entity does not already have
+ * one.
+ *
+ * @param multipart
+ * the multipart to set as body.
+ * @param parameters
+ * additional parameters for the Content-Type header field.
+ */
+ public void setMultipart(Multipart multipart, Map parameters) {
+ String mimeType = "multipart/" + multipart.getSubType();
+ if (!parameters.containsKey("boundary")) {
+ parameters = new HashMap(parameters);
+ parameters.put("boundary", newUniqueBoundary());
+ }
+
+ setBody(multipart, mimeType, parameters);
+ }
+
+ /**
+ * Sets the specified TextBody
as body of this entity and the
+ * content type to "text/plain". A Header
is
+ * created if this entity does not already have one.
+ *
+ * @param textBody
+ * the TextBody
to set as body.
+ * @see org.apache.james.mime4j.message.BodyFactory#textBody(String)
+ */
+ public void setText(TextBody textBody) {
+ setText(textBody, "plain");
+ }
+
+ /**
+ * Sets the specified TextBody
as body of this entity. Also
+ * sets the content type according to the specified sub-type. A
+ * Header
is created if this entity does not already have
+ * one.
+ *
+ * @param textBody
+ * the TextBody
to set as body.
+ * @param subtype
+ * the text subtype (e.g. "plain", "html" or
+ * "xml").
+ * @see org.apache.james.mime4j.message.BodyFactory#textBody(String)
+ */
+ public void setText(TextBody textBody, String subtype) {
+ String mimeType = "text/" + subtype;
+
+ Map parameters = null;
+ String mimeCharset = textBody.getMimeCharset();
+ if (mimeCharset != null && !mimeCharset.equalsIgnoreCase("us-ascii")) {
+ parameters = Collections.singletonMap("charset", mimeCharset);
+ }
+
+ setBody(textBody, mimeType, parameters);
+ }
+
+ /**
+ * Sets the body of this entity and sets the content-type to the specified
+ * value. A Header
is created if this entity does not already
+ * have one.
+ *
+ * @param body
+ * the body.
+ * @param mimeType
+ * the MIME media type of the specified body
+ * ("type/subtype").
+ */
+ public void setBody(Body body, String mimeType) {
+ setBody(body, mimeType, null);
+ }
+
+ /**
+ * Sets the body of this entity and sets the content-type to the specified
+ * value. A Header
is created if this entity does not already
+ * have one.
+ *
+ * @param body
+ * the body.
+ * @param mimeType
+ * the MIME media type of the specified body
+ * ("type/subtype").
+ * @param parameters
+ * additional parameters for the Content-Type header field.
+ */
+ public void setBody(Body body, String mimeType,
+ Map parameters) {
+ setBody(body);
+
+ Header header = obtainHeader();
+ header.setField(newContentType(mimeType, parameters));
+ }
+
+ /**
+ * Determines the MIME type of this Entity
. The MIME type
+ * is derived by looking at the parent's Content-Type field if no
+ * Content-Type field is set for this Entity
.
+ *
+ * @return the MIME type.
+ */
+ public String getMimeType() {
+ ContentTypeField child =
+ getContentTypeField();
+ ContentTypeField parent = getParent() != null
+ ? (ContentTypeField) getParent().getHeader().
+ getField(FieldName.CONTENT_TYPE)
+ : null;
+
+ return calcMimeType(child, parent);
+ }
+
+ private ContentTypeField getContentTypeField() {
+ return (ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE);
+ }
+
+ /**
+ * Determines the MIME character set encoding of this Entity
.
+ *
+ * @return the MIME character set encoding.
+ */
+ public String getCharset() {
+ return calcCharset((ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE));
+ }
+
+ /**
+ * Determines the transfer encoding of this Entity
.
+ *
+ * @return the transfer encoding.
+ */
+ public String getContentTransferEncoding() {
+ ContentTransferEncodingField f = (ContentTransferEncodingField)
+ getHeader().getField(FieldName.CONTENT_TRANSFER_ENCODING);
+
+ return calcTransferEncoding(f);
+ }
+
+ /**
+ * Sets the transfer encoding of this Entity
to the specified
+ * value.
+ *
+ * @param contentTransferEncoding
+ * transfer encoding to use.
+ */
+ public void setContentTransferEncoding(String contentTransferEncoding) {
+ Header header = obtainHeader();
+ header.setField(newContentTransferEncoding(contentTransferEncoding));
+ }
+
+ /**
+ * Return the disposition type of the content disposition of this
+ * Entity
.
+ *
+ * @return the disposition type or null
if no disposition
+ * type has been set.
+ */
+ public String getDispositionType() {
+ ContentDispositionField field = obtainField(FieldName.CONTENT_DISPOSITION);
+ if (field == null)
+ return null;
+
+ return field.getDispositionType();
+ }
+
+ /**
+ * Sets the content disposition of this Entity
to the
+ * specified disposition type. No filename, size or date parameters
+ * are included in the content disposition.
+ *
+ * @param dispositionType
+ * disposition type value (usually inline
or
+ * attachment
).
+ */
+ public void setContentDisposition(String dispositionType) {
+ Header header = obtainHeader();
+ header.setField(newContentDisposition(dispositionType, null, -1, null,
+ null, null));
+ }
+
+ /**
+ * Sets the content disposition of this Entity
to the
+ * specified disposition type and filename. No size or date parameters are
+ * included in the content disposition.
+ *
+ * @param dispositionType
+ * disposition type value (usually inline
or
+ * attachment
).
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should not be included.
+ */
+ public void setContentDisposition(String dispositionType, String filename) {
+ Header header = obtainHeader();
+ header.setField(newContentDisposition(dispositionType, filename, -1,
+ null, null, null));
+ }
+
+ /**
+ * Sets the content disposition of this Entity
to the
+ * specified values. No date parameters are included in the content
+ * disposition.
+ *
+ * @param dispositionType
+ * disposition type value (usually inline
or
+ * attachment
).
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should not be included.
+ * @param size
+ * size parameter value or -1
if the parameter
+ * should not be included.
+ */
+ public void setContentDisposition(String dispositionType, String filename,
+ long size) {
+ Header header = obtainHeader();
+ header.setField(newContentDisposition(dispositionType, filename, size,
+ null, null, null));
+ }
+
+ /**
+ * Sets the content disposition of this Entity
to the
+ * specified values.
+ *
+ * @param dispositionType
+ * disposition type value (usually inline
or
+ * attachment
).
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should not be included.
+ * @param size
+ * size parameter value or -1
if the parameter
+ * should not be included.
+ * @param creationDate
+ * creation-date parameter value or null
if the
+ * parameter should not be included.
+ * @param modificationDate
+ * modification-date parameter value or null
if
+ * the parameter should not be included.
+ * @param readDate
+ * read-date parameter value or null
if the
+ * parameter should not be included.
+ */
+ public void setContentDisposition(String dispositionType, String filename,
+ long size, Date creationDate, Date modificationDate, Date readDate) {
+ Header header = obtainHeader();
+ header.setField(newContentDisposition(dispositionType, filename, size,
+ creationDate, modificationDate, readDate));
+ }
+
+ /**
+ * Returns the filename parameter of the content disposition of this
+ * Entity
.
+ *
+ * @return the filename parameter of the content disposition or
+ * null
if the filename has not been set.
+ */
+ public String getFilename() {
+ ContentDispositionField field = obtainField(FieldName.CONTENT_DISPOSITION);
+ if (field == null)
+ return null;
+
+ return field.getFilename();
+ }
+
+ /**
+ * Sets the filename parameter of the content disposition of this
+ * Entity
to the specified value. If this entity does not
+ * have a content disposition header field a new one with disposition type
+ * attachment
is created.
+ *
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should be removed.
+ */
+ public void setFilename(String filename) {
+ Header header = obtainHeader();
+ ContentDispositionField field = (ContentDispositionField) header
+ .getField(FieldName.CONTENT_DISPOSITION);
+ if (field == null) {
+ if (filename != null) {
+ header.setField(newContentDisposition(
+ ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT,
+ filename, -1, null, null, null));
+ }
+ } else {
+ String dispositionType = field.getDispositionType();
+ Map parameters = new HashMap(field
+ .getParameters());
+ if (filename == null) {
+ parameters.remove(ContentDispositionField.PARAM_FILENAME);
+ } else {
+ parameters
+ .put(ContentDispositionField.PARAM_FILENAME, filename);
+ }
+ header.setField(newContentDisposition(dispositionType, parameters));
+ }
+ }
+
+ /**
+ * Determines if the MIME type of this Entity
matches the
+ * given one. MIME types are case-insensitive.
+ *
+ * @param type the MIME type to match against.
+ * @return true
on match, false
otherwise.
+ */
+ public boolean isMimeType(String type) {
+ return getMimeType().equalsIgnoreCase(type);
+ }
+
+ /**
+ * Determines if the MIME type of this Entity
is
+ * multipart/*
. Since multipart-entities must have
+ * a boundary parameter in the Content-Type
field this
+ * method returns false
if no boundary exists.
+ *
+ * @return true
on match, false
otherwise.
+ */
+ public boolean isMultipart() {
+ ContentTypeField f = getContentTypeField();
+ return f != null
+ && f.getBoundary() != null
+ && getMimeType().startsWith(
+ ContentTypeField.TYPE_MULTIPART_PREFIX);
+ }
+
+ /**
+ * Disposes of the body of this entity. Note that the dispose call does not
+ * get forwarded to the parent entity of this Entity.
+ *
+ * Subclasses that need to free resources should override this method and
+ * invoke super.dispose().
+ *
+ * @see org.apache.james.mime4j.dom.Disposable#dispose()
+ */
+ public void dispose() {
+ if (body != null) {
+ body.dispose();
+ }
+ }
+
+ /**
+ * Obtains the header of this entity. Creates and sets a new header if this
+ * entity's header is currently null
.
+ *
+ * @return the header of this entity; never null
.
+ */
+ Header obtainHeader() {
+ if (header == null) {
+ header = new Header();
+ }
+ return header;
+ }
+
+ /**
+ * Obtains the header field with the specified name.
+ *
+ * @param
+ * concrete field type.
+ * @param fieldName
+ * name of the field to retrieve.
+ * @return the header field or null
if this entity has no
+ * header or the header contains no such field.
+ */
+ F obtainField(String fieldName) {
+ Header header = getHeader();
+ if (header == null)
+ return null;
+
+ @SuppressWarnings("unchecked")
+ F field = (F) header.getField(fieldName);
+ return field;
+ }
+
+ protected abstract String newUniqueBoundary();
+
+ protected abstract ContentDispositionField newContentDisposition(
+ String dispositionType, String filename, long size,
+ Date creationDate, Date modificationDate, Date readDate);
+
+ protected abstract ContentDispositionField newContentDisposition(
+ String dispositionType, Map parameters);
+
+ protected abstract ContentTypeField newContentType(String mimeType,
+ Map parameters);
+
+ protected abstract ContentTransferEncodingField newContentTransferEncoding(
+ String contentTransferEncoding);
+
+ protected abstract String calcMimeType(ContentTypeField child, ContentTypeField parent);
+
+ protected abstract String calcTransferEncoding(ContentTransferEncodingField f);
+
+ protected abstract String calcCharset(ContentTypeField contentType);
+}
diff --git a/src/org/apache/james/mime4j/dom/Header.java b/src/org/apache/james/mime4j/dom/Header.java
new file mode 100644
index 000000000..9c134bf80
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/Header.java
@@ -0,0 +1,204 @@
+/****************************************************************
+ * 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.dom;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.james.mime4j.dom.field.Field;
+
+/**
+ * The header of an entity (see RFC 2045).
+ */
+public class Header implements Iterable {
+
+ private List fields = new LinkedList();
+ private Map> fieldMap = new HashMap>();
+
+ /**
+ * Creates a new empty Header
.
+ */
+ public Header() {
+ }
+
+ /**
+ * Creates a new Header
from the specified
+ * Header
. The Header
instance is initialized
+ * with a copy of the list of {@link Field}s of the specified
+ * Header
. The Field
objects are not copied
+ * because they are immutable and can safely be shared between headers.
+ *
+ * @param other
+ * header to copy.
+ */
+ public Header(Header other) {
+ for (Field otherField : other.fields) {
+ addField(otherField);
+ }
+ }
+
+ /**
+ * Adds a field to the end of the list of fields.
+ *
+ * @param field the field to add.
+ */
+ public void addField(Field field) {
+ List values = fieldMap.get(field.getName().toLowerCase());
+ if (values == null) {
+ values = new LinkedList();
+ fieldMap.put(field.getName().toLowerCase(), values);
+ }
+ values.add(field);
+ fields.add(field);
+ }
+
+ /**
+ * Gets the fields of this header. The returned list will not be
+ * modifiable.
+ *
+ * @return the list of Field
objects.
+ */
+ public List getFields() {
+ return Collections.unmodifiableList(fields);
+ }
+
+ /**
+ * Gets a Field
given a field name. If there are multiple
+ * such fields defined in this header the first one will be returned.
+ *
+ * @param name the field name (e.g. From, Subject).
+ * @return the field or null
if none found.
+ */
+ public Field getField(String name) {
+ List l = fieldMap.get(name.toLowerCase());
+ if (l != null && !l.isEmpty()) {
+ return l.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Gets all Field
s having the specified field name.
+ *
+ * @param name the field name (e.g. From, Subject).
+ * @return the list of fields.
+ */
+ public List getFields(final String name) {
+ final String lowerCaseName = name.toLowerCase();
+ final List l = fieldMap.get(lowerCaseName);
+ final List results;
+ if (l == null || l.isEmpty()) {
+ results = Collections.emptyList();
+ } else {
+ results = Collections.unmodifiableList(l);
+ }
+ return results;
+ }
+
+ /**
+ * Returns an iterator over the list of fields of this header.
+ *
+ * @return an iterator.
+ */
+ public Iterator iterator() {
+ return Collections.unmodifiableList(fields).iterator();
+ }
+
+ /**
+ * Removes all Field
s having the specified field name.
+ *
+ * @param name
+ * the field name (e.g. From, Subject).
+ * @return number of fields removed.
+ */
+ public int removeFields(String name) {
+ final String lowerCaseName = name.toLowerCase();
+ List removed = fieldMap.remove(lowerCaseName);
+ if (removed == null || removed.isEmpty())
+ return 0;
+
+ for (Iterator iterator = fields.iterator(); iterator.hasNext();) {
+ Field field = iterator.next();
+ if (field.getName().equalsIgnoreCase(name))
+ iterator.remove();
+ }
+
+ return removed.size();
+ }
+
+ /**
+ * Sets or replaces a field. This method is useful for header fields such as
+ * Subject or Message-ID that should not occur more than once in a message.
+ *
+ * If this Header
does not already contain a header field of
+ * the same name as the given field then it is added to the end of the list
+ * of fields (same behavior as {@link #addField(Field)}). Otherwise the
+ * first occurrence of a field with the same name is replaced by the given
+ * field and all further occurrences are removed.
+ *
+ * @param field the field to set.
+ */
+ public void setField(Field field) {
+ final String lowerCaseName = field.getName().toLowerCase();
+ List l = fieldMap.get(lowerCaseName);
+ if (l == null || l.isEmpty()) {
+ addField(field);
+ return;
+ }
+
+ l.clear();
+ l.add(field);
+
+ int firstOccurrence = -1;
+ int index = 0;
+ for (Iterator iterator = fields.iterator(); iterator.hasNext(); index++) {
+ Field f = iterator.next();
+ if (f.getName().equalsIgnoreCase(field.getName())) {
+ iterator.remove();
+
+ if (firstOccurrence == -1)
+ firstOccurrence = index;
+ }
+ }
+
+ fields.add(firstOccurrence, field);
+ }
+
+ /**
+ * Return Header Object as String representation. Each headerline is
+ * seperated by "\r\n"
+ *
+ * @return headers
+ */
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder(128);
+ for (Field field : fields) {
+ str.append(field.toString());
+ str.append("\r\n");
+ }
+ return str.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/dom/Message.java b/src/org/apache/james/mime4j/dom/Message.java
new file mode 100644
index 000000000..35fe2e80e
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/Message.java
@@ -0,0 +1,512 @@
+/****************************************************************
+ * 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.dom;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.address.MailboxList;
+import org.apache.james.mime4j.dom.field.AddressListField;
+import org.apache.james.mime4j.dom.field.DateTimeField;
+import org.apache.james.mime4j.dom.field.Field;
+import org.apache.james.mime4j.dom.field.FieldName;
+import org.apache.james.mime4j.dom.field.MailboxField;
+import org.apache.james.mime4j.dom.field.MailboxListField;
+import org.apache.james.mime4j.dom.field.UnstructuredField;
+
+public abstract class Message extends Entity implements Body {
+
+ /**
+ * Write the content to the given output stream using the
+ * {@link org.apache.james.mime4j.message.MessageWriter#DEFAULT default} message writer.
+ *
+ * @param out
+ * the output stream to write to.
+ * @throws IOException
+ * in case of an I/O error
+ * @see org.apache.james.mime4j.message.MessageWriter
+ */
+ public abstract void writeTo(OutputStream out) throws IOException;
+
+ /**
+ * Returns the value of the Message-ID header field of this message
+ * or null
if it is not present.
+ *
+ * @return the identifier of this message.
+ */
+ public String getMessageId() {
+ Field field = obtainField(FieldName.MESSAGE_ID);
+ if (field == null)
+ return null;
+
+ return field.getBody();
+ }
+
+ /**
+ * Creates and sets a new Message-ID header field for this message.
+ * A Header
is created if this message does not already have
+ * one.
+ *
+ * @param hostname
+ * host name to be included in the identifier or
+ * null
if no host name should be included.
+ */
+ public void createMessageId(String hostname) {
+ Header header = obtainHeader();
+
+ header.setField(newMessageId(hostname));
+ }
+
+ protected abstract Field newMessageId(String hostname);
+
+ /**
+ * Returns the (decoded) value of the Subject header field of this
+ * message or null
if it is not present.
+ *
+ * @return the subject of this message.
+ */
+ public String getSubject() {
+ UnstructuredField field = obtainField(FieldName.SUBJECT);
+ if (field == null)
+ return null;
+
+ return field.getValue();
+ }
+
+ /**
+ * Sets the Subject header field for this message. The specified
+ * string may contain non-ASCII characters, in which case it gets encoded as
+ * an 'encoded-word' automatically. A Header
is created if
+ * this message does not already have one.
+ *
+ * @param subject
+ * subject to set or null
to remove the subject
+ * header field.
+ */
+ public void setSubject(String subject) {
+ Header header = obtainHeader();
+
+ if (subject == null) {
+ header.removeFields(FieldName.SUBJECT);
+ } else {
+ header.setField(newSubject(subject));
+ }
+ }
+
+ /**
+ * Returns the value of the Date header field of this message as
+ * Date
object or null
if it is not present.
+ *
+ * @return the date of this message.
+ */
+ public Date getDate() {
+ DateTimeField dateField = obtainField(FieldName.DATE);
+ if (dateField == null)
+ return null;
+
+ return dateField.getDate();
+ }
+
+ /**
+ * Sets the Date header field for this message. This method uses the
+ * default TimeZone
of this host to encode the specified
+ * Date
object into a string.
+ *
+ * @param date
+ * date to set or null
to remove the date header
+ * field.
+ */
+ public void setDate(Date date) {
+ setDate(date, null);
+ }
+
+ /**
+ * Sets the Date header field for this message. The specified
+ * TimeZone
is used to encode the specified Date
+ * object into a string.
+ *
+ * @param date
+ * date to set or null
to remove the date header
+ * field.
+ * @param zone
+ * a time zone.
+ */
+ public void setDate(Date date, TimeZone zone) {
+ Header header = obtainHeader();
+
+ if (date == null) {
+ header.removeFields(FieldName.DATE);
+ } else {
+ header.setField(newDate(date, zone));
+ }
+ }
+
+ /**
+ * Returns the value of the Sender header field of this message as
+ * Mailbox
object or null
if it is not
+ * present.
+ *
+ * @return the sender of this message.
+ */
+ public Mailbox getSender() {
+ return getMailbox(FieldName.SENDER);
+ }
+
+ /**
+ * Sets the Sender header field of this message to the specified
+ * mailbox address.
+ *
+ * @param sender
+ * address to set or null
to remove the header
+ * field.
+ */
+ public void setSender(Mailbox sender) {
+ setMailbox(FieldName.SENDER, sender);
+ }
+
+ /**
+ * Returns the value of the From header field of this message as
+ * MailboxList
object or null
if it is not
+ * present.
+ *
+ * @return value of the from field of this message.
+ */
+ public MailboxList getFrom() {
+ return getMailboxList(FieldName.FROM);
+ }
+
+ /**
+ * Sets the From header field of this message to the specified
+ * mailbox address.
+ *
+ * @param from
+ * address to set or null
to remove the header
+ * field.
+ */
+ public void setFrom(Mailbox from) {
+ setMailboxList(FieldName.FROM, from);
+ }
+
+ /**
+ * Sets the From header field of this message to the specified
+ * mailbox addresses.
+ *
+ * @param from
+ * addresses to set or null
or no arguments to
+ * remove the header field.
+ */
+ public void setFrom(Mailbox... from) {
+ setMailboxList(FieldName.FROM, from);
+ }
+
+ /**
+ * Sets the From header field of this message to the specified
+ * mailbox addresses.
+ *
+ * @param from
+ * addresses to set or null
or an empty collection
+ * to remove the header field.
+ */
+ public void setFrom(Collection from) {
+ setMailboxList(FieldName.FROM, from);
+ }
+
+ /**
+ * Returns the value of the To header field of this message as
+ * AddressList
object or null
if it is not
+ * present.
+ *
+ * @return value of the to field of this message.
+ */
+ public AddressList getTo() {
+ return getAddressList(FieldName.TO);
+ }
+
+ /**
+ * Sets the To header field of this message to the specified
+ * address.
+ *
+ * @param to
+ * address to set or null
to remove the header
+ * field.
+ */
+ public void setTo(Address to) {
+ setAddressList(FieldName.TO, to);
+ }
+
+ /**
+ * Sets the To header field of this message to the specified
+ * addresses.
+ *
+ * @param to
+ * addresses to set or null
or no arguments to
+ * remove the header field.
+ */
+ public void setTo(Address... to) {
+ setAddressList(FieldName.TO, to);
+ }
+
+ /**
+ * Sets the To header field of this message to the specified
+ * addresses.
+ *
+ * @param to
+ * addresses to set or null
or an empty collection
+ * to remove the header field.
+ */
+ public void setTo(Collection to) {
+ setAddressList(FieldName.TO, to);
+ }
+
+ /**
+ * Returns the value of the Cc header field of this message as
+ * AddressList
object or null
if it is not
+ * present.
+ *
+ * @return value of the cc field of this message.
+ */
+ public AddressList getCc() {
+ return getAddressList(FieldName.CC);
+ }
+
+ /**
+ * Sets the Cc header field of this message to the specified
+ * address.
+ *
+ * @param cc
+ * address to set or null
to remove the header
+ * field.
+ */
+ public void setCc(Address cc) {
+ setAddressList(FieldName.CC, cc);
+ }
+
+ /**
+ * Sets the Cc header field of this message to the specified
+ * addresses.
+ *
+ * @param cc
+ * addresses to set or null
or no arguments to
+ * remove the header field.
+ */
+ public void setCc(Address... cc) {
+ setAddressList(FieldName.CC, cc);
+ }
+
+ /**
+ * Sets the Cc header field of this message to the specified
+ * addresses.
+ *
+ * @param cc
+ * addresses to set or null
or an empty collection
+ * to remove the header field.
+ */
+ public void setCc(Collection cc) {
+ setAddressList(FieldName.CC, cc);
+ }
+
+ /**
+ * Returns the value of the Bcc header field of this message as
+ * AddressList
object or null
if it is not
+ * present.
+ *
+ * @return value of the bcc field of this message.
+ */
+ public AddressList getBcc() {
+ return getAddressList(FieldName.BCC);
+ }
+
+ /**
+ * Sets the Bcc header field of this message to the specified
+ * address.
+ *
+ * @param bcc
+ * address to set or null
to remove the header
+ * field.
+ */
+ public void setBcc(Address bcc) {
+ setAddressList(FieldName.BCC, bcc);
+ }
+
+ /**
+ * Sets the Bcc header field of this message to the specified
+ * addresses.
+ *
+ * @param bcc
+ * addresses to set or null
or no arguments to
+ * remove the header field.
+ */
+ public void setBcc(Address... bcc) {
+ setAddressList(FieldName.BCC, bcc);
+ }
+
+ /**
+ * Sets the Bcc header field of this message to the specified
+ * addresses.
+ *
+ * @param bcc
+ * addresses to set or null
or an empty collection
+ * to remove the header field.
+ */
+ public void setBcc(Collection bcc) {
+ setAddressList(FieldName.BCC, bcc);
+ }
+
+ /**
+ * Returns the value of the Reply-To header field of this message as
+ * AddressList
object or null
if it is not
+ * present.
+ *
+ * @return value of the reply to field of this message.
+ */
+ public AddressList getReplyTo() {
+ return getAddressList(FieldName.REPLY_TO);
+ }
+
+ /**
+ * Sets the Reply-To header field of this message to the specified
+ * address.
+ *
+ * @param replyTo
+ * address to set or null
to remove the header
+ * field.
+ */
+ public void setReplyTo(Address replyTo) {
+ setAddressList(FieldName.REPLY_TO, replyTo);
+ }
+
+ /**
+ * Sets the Reply-To header field of this message to the specified
+ * addresses.
+ *
+ * @param replyTo
+ * addresses to set or null
or no arguments to
+ * remove the header field.
+ */
+ public void setReplyTo(Address... replyTo) {
+ setAddressList(FieldName.REPLY_TO, replyTo);
+ }
+
+ /**
+ * Sets the Reply-To header field of this message to the specified
+ * addresses.
+ *
+ * @param replyTo
+ * addresses to set or null
or an empty collection
+ * to remove the header field.
+ */
+ public void setReplyTo(Collection replyTo) {
+ setAddressList(FieldName.REPLY_TO, replyTo);
+ }
+
+ private Mailbox getMailbox(String fieldName) {
+ MailboxField field = obtainField(fieldName);
+ if (field == null)
+ return null;
+
+ return field.getMailbox();
+ }
+
+ private void setMailbox(String fieldName, Mailbox mailbox) {
+ Header header = obtainHeader();
+
+ if (mailbox == null) {
+ header.removeFields(fieldName);
+ } else {
+ header.setField(newMailbox(fieldName, mailbox));
+ }
+ }
+
+ private MailboxList getMailboxList(String fieldName) {
+ MailboxListField field = obtainField(fieldName);
+ if (field == null)
+ return null;
+
+ return field.getMailboxList();
+ }
+
+ private void setMailboxList(String fieldName, Mailbox mailbox) {
+ setMailboxList(fieldName, mailbox == null ? null : Collections
+ .singleton(mailbox));
+ }
+
+ private void setMailboxList(String fieldName, Mailbox... mailboxes) {
+ setMailboxList(fieldName, mailboxes == null ? null : Arrays
+ .asList(mailboxes));
+ }
+
+ private void setMailboxList(String fieldName, Collection mailboxes) {
+ Header header = obtainHeader();
+
+ if (mailboxes == null || mailboxes.isEmpty()) {
+ header.removeFields(fieldName);
+ } else {
+ header.setField(newMailboxList(fieldName, mailboxes));
+ }
+ }
+
+ private AddressList getAddressList(String fieldName) {
+ AddressListField field = obtainField(fieldName);
+ if (field == null)
+ return null;
+
+ return field.getAddressList();
+ }
+
+ private void setAddressList(String fieldName, Address address) {
+ setAddressList(fieldName, address == null ? null : Collections
+ .singleton(address));
+ }
+
+ private void setAddressList(String fieldName, Address... addresses) {
+ setAddressList(fieldName, addresses == null ? null : Arrays
+ .asList(addresses));
+ }
+
+ private void setAddressList(String fieldName, Collection addresses) {
+ Header header = obtainHeader();
+
+ if (addresses == null || addresses.isEmpty()) {
+ header.removeFields(fieldName);
+ } else {
+ header.setField(newAddressList(fieldName, addresses));
+ }
+ }
+
+ protected abstract AddressListField newAddressList(String fieldName, Collection addresses);
+
+ protected abstract UnstructuredField newSubject(String subject);
+
+ protected abstract DateTimeField newDate(Date date, TimeZone zone);
+
+ protected abstract MailboxField newMailbox(String fieldName, Mailbox mailbox);
+
+ protected abstract MailboxListField newMailboxList(String fieldName, Collection mailboxes);
+
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/MessageBuilder.java b/src/org/apache/james/mime4j/dom/MessageBuilder.java
new file mode 100644
index 000000000..a8affa6a1
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/MessageBuilder.java
@@ -0,0 +1,46 @@
+/****************************************************************
+ * 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.dom;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.DecodeMonitor;
+
+/**
+ * Defines the API to obtain Message instances from a mime stream.
+ */
+public abstract class MessageBuilder {
+
+ public abstract Message newMessage();
+
+ public abstract Message newMessage(Message source);
+
+ public abstract Message parse(InputStream source) throws MimeException, IOException;
+
+ public abstract void setDecodeMonitor(
+ DecodeMonitor decodeMonitor);
+
+ public abstract void setContentDecoding(boolean contentDecoding);
+
+ public abstract void setFlatMode();
+
+}
diff --git a/src/org/apache/james/mime4j/dom/MessageBuilderFactory.java b/src/org/apache/james/mime4j/dom/MessageBuilderFactory.java
new file mode 100644
index 000000000..3c88c1cfc
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/MessageBuilderFactory.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * 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.dom;
+
+import org.apache.james.mime4j.MimeException;
+
+/**
+ * A MessageBuilderFactory is used to create EntityBuilder instances.
+ *
+ * MessageBuilderFactory.newInstance() is used to get access to an implementation
+ * of MessageBuilderFactory.
+ * Then the method newMessageBuilder is used to create a new EntityBuilder object.
+ */
+public abstract class MessageBuilderFactory {
+
+ public abstract MessageBuilder newMessageBuilder() throws MimeException;
+
+ public static MessageBuilderFactory newInstance() throws MimeException {
+ return ServiceLoader.load(MessageBuilderFactory.class);
+ }
+
+ public abstract void setAttribute(String name, Object value) throws IllegalArgumentException;
+
+}
diff --git a/src/org/apache/james/mime4j/dom/Multipart.java b/src/org/apache/james/mime4j/dom/Multipart.java
new file mode 100644
index 000000000..8101faf4a
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/Multipart.java
@@ -0,0 +1,238 @@
+/****************************************************************
+ * 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.dom;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Represents a MIME multipart body (see RFC 2045).A multipart body has a
+ * ordered list of body parts. The multipart body also has a preamble and
+ * epilogue. The preamble consists of whatever characters appear before the
+ * first body part while the epilogue consists of whatever characters come after
+ * the last body part.
+ */
+public abstract class Multipart implements Body {
+
+ protected List bodyParts = new LinkedList();
+ private Entity parent = null;
+
+ private String subType;
+
+ /**
+ * Creates a new empty Multipart
instance.
+ */
+ public Multipart(String subType) {
+ this.subType = subType;
+ }
+
+ /**
+ * Gets the multipart sub-type. E.g. alternative
(the
+ * default) or parallel
. See RFC 2045 for common sub-types
+ * and their meaning.
+ *
+ * @return the multipart sub-type.
+ */
+ public String getSubType() {
+ return subType;
+ }
+
+ /**
+ * Sets the multipart sub-type. E.g. alternative
or
+ * parallel
. See RFC 2045 for common sub-types and their
+ * meaning.
+ *
+ * @param subType
+ * the sub-type.
+ */
+ public void setSubType(String subType) {
+ this.subType = subType;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.Body#getParent()
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.Body#setParent(org.apache.james.mime4j.dom.Entity)
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ for (Entity bodyPart : bodyParts) {
+ bodyPart.setParent(parent);
+ }
+ }
+
+ /**
+ * Returns the number of body parts.
+ *
+ * @return number of Entity
objects.
+ */
+ public int getCount() {
+ return bodyParts.size();
+ }
+
+ /**
+ * Gets the list of body parts. The list is immutable.
+ *
+ * @return the list of Entity
objects.
+ */
+ public List getBodyParts() {
+ return Collections.unmodifiableList(bodyParts);
+ }
+
+ /**
+ * Sets the list of body parts.
+ *
+ * @param bodyParts
+ * the new list of Entity
objects.
+ */
+ public void setBodyParts(List bodyParts) {
+ this.bodyParts = bodyParts;
+ for (Entity bodyPart : bodyParts) {
+ bodyPart.setParent(parent);
+ }
+ }
+
+ /**
+ * Adds a body part to the end of the list of body parts.
+ *
+ * @param bodyPart
+ * the body part.
+ */
+ public void addBodyPart(Entity bodyPart) {
+ if (bodyPart == null)
+ throw new IllegalArgumentException();
+
+ bodyParts.add(bodyPart);
+ bodyPart.setParent(parent);
+ }
+
+ /**
+ * Inserts a body part at the specified position in the list of body parts.
+ *
+ * @param bodyPart
+ * the body part.
+ * @param index
+ * index at which the specified body part is to be inserted.
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range (index < 0 || index >
+ * getCount()).
+ */
+ public void addBodyPart(Entity bodyPart, int index) {
+ if (bodyPart == null)
+ throw new IllegalArgumentException();
+
+ bodyParts.add(index, bodyPart);
+ bodyPart.setParent(parent);
+ }
+
+ /**
+ * Removes the body part at the specified position in the list of body
+ * parts.
+ *
+ * @param index
+ * index of the body part to be removed.
+ * @return the removed body part.
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range (index < 0 || index >=
+ * getCount()).
+ */
+ public Entity removeBodyPart(int index) {
+ Entity bodyPart = bodyParts.remove(index);
+ bodyPart.setParent(null);
+ return bodyPart;
+ }
+
+ /**
+ * Replaces the body part at the specified position in the list of body
+ * parts with the specified body part.
+ *
+ * @param bodyPart
+ * body part to be stored at the specified position.
+ * @param index
+ * index of body part to replace.
+ * @return the replaced body part.
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range (index < 0 || index >=
+ * getCount()).
+ */
+ public Entity replaceBodyPart(Entity bodyPart, int index) {
+ if (bodyPart == null)
+ throw new IllegalArgumentException();
+
+ Entity replacedEntity = bodyParts.set(index, bodyPart);
+ if (bodyPart == replacedEntity)
+ throw new IllegalArgumentException(
+ "Cannot replace body part with itself");
+
+ bodyPart.setParent(parent);
+ replacedEntity.setParent(null);
+
+ return replacedEntity;
+ }
+
+ /**
+ * Gets the preamble or null if the message has no preamble.
+ *
+ * @return the preamble.
+ */
+ public abstract String getPreamble();
+
+ /**
+ * Sets the preamble with a value or null to remove the preamble.
+ *
+ * @param preamble
+ * the preamble.
+ */
+ public abstract void setPreamble(String preamble);
+
+ /**
+ * Gets the epilogue or null if the message has no epilogue
+ *
+ * @return the epilogue.
+ */
+ public abstract String getEpilogue();
+
+ /**
+ * Sets the epilogue value, or remove it if the value passed is null.
+ *
+ * @param epilogue
+ * the epilogue.
+ */
+ public abstract void setEpilogue(String epilogue);
+
+ /**
+ * Disposes of the BodyParts of this Multipart. Note that the dispose call
+ * does not get forwarded to the parent entity of this Multipart.
+ *
+ * @see org.apache.james.mime4j.dom.Disposable#dispose()
+ */
+ public void dispose() {
+ for (Entity bodyPart : bodyParts) {
+ bodyPart.dispose();
+ }
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/dom/ServiceLoader.java b/src/org/apache/james/mime4j/dom/ServiceLoader.java
new file mode 100644
index 000000000..94f5fede2
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/ServiceLoader.java
@@ -0,0 +1,95 @@
+/****************************************************************
+ * 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.dom;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+
+/**
+ * Utility class to load Service Providers (SPI).
+ * This will deprecated as soon as mime4j will be upgraded to Java6
+ * as Java6 has javax.util.ServiceLoader as a core class.
+ */
+class ServiceLoader {
+
+ private ServiceLoader() {
+ }
+
+ /**
+ * Loads a Service Provider for the given interface/class (SPI).
+ */
+ static T load(Class spiClass) {
+ String spiResURI = "META-INF/services/" + spiClass.getName();
+ ClassLoader classLoader = spiClass.getClassLoader();
+ Enumeration resources;
+ try {
+ resources = classLoader.getResources(spiResURI);
+ } catch (IOException e) {
+ return null;
+ }
+
+ while (resources.hasMoreElements()) {
+ URL resource = resources.nextElement();
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(resource
+ .openStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ int cmtIdx = line.indexOf('#');
+ if (cmtIdx != -1) {
+ line = line.substring(0, cmtIdx);
+ line = line.trim();
+ }
+
+ if (line.length() == 0) {
+ continue;
+ }
+
+ Class> implClass;
+ try {
+ implClass = classLoader.loadClass(line);
+
+ if (spiClass.isAssignableFrom(implClass)) {
+ Object impl = implClass.newInstance();
+ return spiClass.cast(impl);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/SingleBody.java b/src/org/apache/james/mime4j/dom/SingleBody.java
new file mode 100644
index 000000000..c75cad0d0
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/SingleBody.java
@@ -0,0 +1,139 @@
+/****************************************************************
+ * 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.dom;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Abstract implementation of a single message body; that is, a body that does
+ * not contain (directly or indirectly) any other child bodies. It also provides
+ * the parent functionality required by bodies.
+ */
+public abstract class SingleBody implements Body {
+
+ private Entity parent = null;
+
+ /**
+ * Sole constructor.
+ */
+ protected SingleBody() {
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.Body#getParent()
+ */
+ public Entity getParent() {
+ return parent;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.Body#setParent(org.apache.james.mime4j.dom.Entity)
+ */
+ public void setParent(Entity parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets a InputStream
which reads the bytes of the body.
+ *
+ * @return the stream, transfer decoded
+ * @throws IOException
+ * on I/O errors.
+ */
+ public abstract InputStream getInputStream() throws IOException;
+
+ /**
+ * Writes this single body to the given stream. The default implementation copies
+ * the input stream obtained by {@link #getInputStream()} to the specified output
+ * stream. May be overwritten by a subclass to improve performance.
+ *
+ * @param out
+ * the stream to write to.
+ * @throws IOException
+ * in case of an I/O error
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ if (out == null)
+ throw new IllegalArgumentException();
+
+ InputStream in = getInputStream();
+ SingleBody.copy(in, out);
+ in.close();
+ }
+
+ /**
+ * Returns a copy of this SingleBody
(optional operation).
+ *
+ * The general contract of this method is as follows:
+ *
+ * - Invoking {@link #getParent()} on the copy returns
null
.
+ * That means that the copy is detached from the parent entity of this
+ * SingleBody
. The copy may get attached to a different
+ * entity later on.
+ * - The underlying content does not have to be copied. Instead it may be
+ * shared between multiple copies of a
SingleBody
.
+ * - If the underlying content is shared by multiple copies the
+ * implementation has to make sure that the content gets deleted when the
+ * last copy gets disposed of (and not before that).
+ *
+ *
+ * This implementation always throws an
+ * UnsupportedOperationException
.
+ *
+ * @return a copy of this SingleBody
.
+ * @throws UnsupportedOperationException
+ * if the copy
operation is not supported by this
+ * single body.
+ */
+ public SingleBody copy() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Subclasses should override this method if they have allocated resources
+ * that need to be freed explicitly (e.g. cannot be simply reclaimed by the
+ * garbage collector).
+ *
+ * The default implementation of this method does nothing.
+ *
+ * @see org.apache.james.mime4j.dom.Disposable#dispose()
+ */
+ public void dispose() {
+ }
+
+ static final int DEFAULT_ENCODING_BUFFER_SIZE = 1024;
+
+ /**
+ * Copies the contents of one stream to the other.
+ * @param in not null
+ * @param out not null
+ * @throws IOException
+ */
+ private static void copy(final InputStream in, final OutputStream out) throws IOException {
+ final byte[] buffer = new byte[DEFAULT_ENCODING_BUFFER_SIZE];
+ int inputLength;
+ while (-1 != (inputLength = in.read(buffer))) {
+ out.write(buffer, 0, inputLength);
+ }
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/message/TextBody.java b/src/org/apache/james/mime4j/dom/TextBody.java
similarity index 76%
rename from src/org/apache/james/mime4j/message/TextBody.java
rename to src/org/apache/james/mime4j/dom/TextBody.java
index cbf24c2e7..9929199d8 100644
--- a/src/org/apache/james/mime4j/message/TextBody.java
+++ b/src/org/apache/james/mime4j/dom/TextBody.java
@@ -17,26 +17,37 @@
* under the License. *
****************************************************************/
-package org.apache.james.mime4j.message;
+package org.apache.james.mime4j.dom;
import java.io.IOException;
import java.io.Reader;
-
/**
* Encapsulates the contents of a text/*
entity body.
- *
- *
- * @version $Id: TextBody.java,v 1.3 2004/10/02 12:41:11 ntherning Exp $
*/
-public interface TextBody extends Body {
-
+public abstract class TextBody extends SingleBody {
+
+ /**
+ * Sole constructor.
+ */
+ protected TextBody() {
+ }
+
+ /**
+ * Returns the MIME charset of this text body.
+ *
+ * @return the MIME charset.
+ */
+ public abstract String getMimeCharset();
+
/**
* Gets a Reader
which may be used to read out the contents
* of this body.
- *
+ *
* @return the Reader
.
- * @throws IOException on I/O errors.
+ * @throws IOException
+ * on I/O errors.
*/
- Reader getReader() throws IOException;
+ public abstract Reader getReader() throws IOException;
+
}
diff --git a/src/org/apache/james/mime4j/field/address/Address.java b/src/org/apache/james/mime4j/dom/address/Address.java
similarity index 60%
rename from src/org/apache/james/mime4j/field/address/Address.java
rename to src/org/apache/james/mime4j/dom/address/Address.java
index 5438eb5b2..3dc73ced3 100644
--- a/src/org/apache/james/mime4j/field/address/Address.java
+++ b/src/org/apache/james/mime4j/dom/address/Address.java
@@ -17,36 +17,32 @@
* under the License. *
****************************************************************/
-package org.apache.james.mime4j.field.address;
+package org.apache.james.mime4j.dom.address;
-import java.util.ArrayList;
+import java.io.Serializable;
+import java.util.List;
/**
- * The abstract base for classes that represent RFC2822 addresses.
- * This includes groups and mailboxes.
- *
- * Currently, no public methods are introduced on this class.
- *
- *
+ * The abstract base for classes that represent RFC2822 addresses. This includes
+ * groups and mailboxes.
*/
-public abstract class Address {
+public abstract class Address implements Serializable {
- /**
- * Adds any mailboxes represented by this address
- * into the given ArrayList. Note that this method
- * has default (package) access, so a doAddMailboxesTo
- * method is needed to allow the behavior to be
- * overridden by subclasses.
- */
- final void addMailboxesTo(ArrayList results) {
- doAddMailboxesTo(results);
- }
-
- /**
- * Adds any mailboxes represented by this address
- * into the given ArrayList. Must be overridden by
- * concrete subclasses.
- */
- protected abstract void doAddMailboxesTo(ArrayList results);
+ private static final long serialVersionUID = 634090661990433426L;
-}
+ /**
+ * Adds any mailboxes represented by this address into the given List. Note
+ * that this method has default (package) access, so a doAddMailboxesTo
+ * method is needed to allow the behavior to be overridden by subclasses.
+ */
+ final void addMailboxesTo(List results) {
+ doAddMailboxesTo(results);
+ }
+
+ /**
+ * Adds any mailboxes represented by this address into the given List. Must
+ * be overridden by concrete subclasses.
+ */
+ protected abstract void doAddMailboxesTo(List results);
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/address/AddressList.java b/src/org/apache/james/mime4j/dom/address/AddressList.java
new file mode 100644
index 000000000..91b7a3df1
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/address/AddressList.java
@@ -0,0 +1,98 @@
+/****************************************************************
+ * 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.dom.address;
+
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An immutable, random-access list of Address objects.
+ */
+public class AddressList extends AbstractList implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List extends Address> addresses;
+
+ /**
+ * @param addresses
+ * A List that contains only Address objects.
+ * @param dontCopy
+ * true iff it is not possible for the addresses list to be
+ * modified by someone else.
+ */
+ public AddressList(List extends Address> addresses, boolean dontCopy) {
+ if (addresses != null)
+ this.addresses = dontCopy ? addresses : new ArrayList(
+ addresses);
+ else
+ this.addresses = Collections.emptyList();
+ }
+
+ /**
+ * The number of elements in this list.
+ */
+ @Override
+ public int size() {
+ return addresses.size();
+ }
+
+ /**
+ * Gets an address.
+ */
+ @Override
+ public Address get(int index) {
+ return addresses.get(index);
+ }
+
+ /**
+ * Returns a flat list of all mailboxes represented in this address list.
+ * Use this if you don't care about grouping.
+ */
+ public MailboxList flatten() {
+ // in the common case, all addresses are mailboxes
+ boolean groupDetected = false;
+ for (Address addr : addresses) {
+ if (!(addr instanceof Mailbox)) {
+ groupDetected = true;
+ break;
+ }
+ }
+
+ if (!groupDetected) {
+ @SuppressWarnings("unchecked")
+ final List mailboxes = (List) addresses;
+ return new MailboxList(mailboxes, true);
+ }
+
+ List results = new ArrayList();
+ for (Address addr : addresses) {
+ addr.addMailboxesTo(results);
+ }
+
+ // copy-on-construct this time, because subclasses
+ // could have held onto a reference to the results
+ return new MailboxList(results, false);
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/dom/address/DomainList.java b/src/org/apache/james/mime4j/dom/address/DomainList.java
new file mode 100644
index 000000000..218e6c2c3
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/address/DomainList.java
@@ -0,0 +1,95 @@
+/****************************************************************
+ * 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.dom.address;
+
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An immutable, random-access list of Strings (that are supposedly domain names
+ * or domain literals).
+ */
+public class DomainList extends AbstractList implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List domains;
+
+ /**
+ * @param domains
+ * A List that contains only String objects.
+ * @param dontCopy
+ * true iff it is not possible for the domains list to be
+ * modified by someone else.
+ */
+ public DomainList(List domains, boolean dontCopy) {
+ if (domains != null)
+ this.domains = dontCopy ? domains : new ArrayList(domains);
+ else
+ this.domains = Collections.emptyList();
+ }
+
+ /**
+ * The number of elements in this list.
+ */
+ @Override
+ public int size() {
+ return domains.size();
+ }
+
+ /**
+ * Gets the domain name or domain literal at the specified index.
+ *
+ * @throws IndexOutOfBoundsException
+ * If index is < 0 or >= size().
+ */
+ @Override
+ public String get(int index) {
+ return domains.get(index);
+ }
+
+ /**
+ * Returns the list of domains formatted as a route string (not including
+ * the trailing ':').
+ */
+ public String toRouteString() {
+ StringBuilder sb = new StringBuilder();
+
+ for (String domain : domains) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+
+ sb.append("@");
+ sb.append(domain);
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return toRouteString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/dom/address/Group.java b/src/org/apache/james/mime4j/dom/address/Group.java
new file mode 100644
index 000000000..14b143339
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/address/Group.java
@@ -0,0 +1,113 @@
+/****************************************************************
+ * 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.dom.address;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A named group of zero or more mailboxes.
+ */
+public class Group extends Address {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String name;
+ private final MailboxList mailboxList;
+
+ /**
+ * @param name
+ * The group name.
+ * @param mailboxes
+ * The mailboxes in this group.
+ */
+ public Group(String name, MailboxList mailboxes) {
+ if (name == null)
+ throw new IllegalArgumentException();
+ if (mailboxes == null)
+ throw new IllegalArgumentException();
+
+ this.name = name;
+ this.mailboxList = mailboxes;
+ }
+
+ /**
+ * @param name
+ * The group name.
+ * @param mailboxes
+ * The mailboxes in this group.
+ */
+ public Group(String name, Mailbox... mailboxes) {
+ this(name, new MailboxList(Arrays.asList(mailboxes), true));
+ }
+
+ /**
+ * @param name
+ * The group name.
+ * @param mailboxes
+ * The mailboxes in this group.
+ */
+ public Group(String name, Collection mailboxes) {
+ this(name, new MailboxList(new ArrayList(mailboxes), true));
+ }
+
+ /**
+ * Returns the group name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the mailboxes in this group.
+ */
+ public MailboxList getMailboxes() {
+ return mailboxList;
+ }
+
+ @Override
+ protected void doAddMailboxesTo(List results) {
+ for (Mailbox mailbox : mailboxList) {
+ results.add(mailbox);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ sb.append(':');
+ boolean first = true;
+ for (Mailbox mailbox : mailboxList) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(' ');
+ sb.append(mailbox);
+ }
+ sb.append(";");
+ return sb.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/dom/address/Mailbox.java b/src/org/apache/james/mime4j/dom/address/Mailbox.java
new file mode 100644
index 000000000..86304bea5
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/address/Mailbox.java
@@ -0,0 +1,204 @@
+/****************************************************************
+ * 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.dom.address;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.james.mime4j.util.LangUtils;
+
+/**
+ * Represents a single e-mail address.
+ */
+public class Mailbox extends Address {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final DomainList EMPTY_ROUTE_LIST = new DomainList(
+ Collections. emptyList(), true);
+
+ private final String name;
+ private final DomainList route;
+ private final String localPart;
+ private final String domain;
+
+ /**
+ * Creates a named mailbox with a route. Routes are obsolete.
+ *
+ * @param name
+ * the name of the e-mail address. May be null
.
+ * @param route
+ * The zero or more domains that make up the route. May be
+ * null
.
+ * @param localPart
+ * The part of the e-mail address to the left of the "@".
+ * @param domain
+ * The part of the e-mail address to the right of the "@".
+ */
+ public Mailbox(String name, DomainList route, String localPart,
+ String domain) {
+ if (localPart == null || localPart.length() == 0)
+ throw new IllegalArgumentException();
+
+ this.name = name == null || name.length() == 0 ? null : name;
+ this.route = route == null ? EMPTY_ROUTE_LIST : route;
+ this.localPart = localPart;
+ this.domain = domain == null || domain.length() == 0 ? null : domain;
+ }
+
+ /**
+ * Creates a named mailbox based on an unnamed mailbox. Package private;
+ * internally used by Builder.
+ */
+ Mailbox(String name, Mailbox baseMailbox) {
+ this(name, baseMailbox.getRoute(), baseMailbox.getLocalPart(),
+ baseMailbox.getDomain());
+ }
+
+ /**
+ * Creates an unnamed mailbox without a route. Routes are obsolete.
+ *
+ * @param localPart
+ * The part of the e-mail address to the left of the "@".
+ * @param domain
+ * The part of the e-mail address to the right of the "@".
+ */
+ public Mailbox(String localPart, String domain) {
+ this(null, null, localPart, domain);
+ }
+
+ /**
+ * Creates an unnamed mailbox with a route. Routes are obsolete.
+ *
+ * @param route
+ * The zero or more domains that make up the route. May be
+ * null
.
+ * @param localPart
+ * The part of the e-mail address to the left of the "@".
+ * @param domain
+ * The part of the e-mail address to the right of the "@".
+ */
+ public Mailbox(DomainList route, String localPart, String domain) {
+ this(null, route, localPart, domain);
+ }
+
+ /**
+ * Creates a named mailbox without a route. Routes are obsolete.
+ *
+ * @param name
+ * the name of the e-mail address. May be null
.
+ * @param localPart
+ * The part of the e-mail address to the left of the "@".
+ * @param domain
+ * The part of the e-mail address to the right of the "@".
+ */
+ public Mailbox(String name, String localPart, String domain) {
+ this(name, null, localPart, domain);
+ }
+
+ /**
+ * Returns the name of the mailbox or null
if it does not
+ * have a name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the route list. If the mailbox does not have a route an empty
+ * domain list is returned.
+ */
+ public DomainList getRoute() {
+ return route;
+ }
+
+ /**
+ * Returns the left part of the e-mail address (before "@").
+ */
+ public String getLocalPart() {
+ return localPart;
+ }
+
+ /**
+ * Returns the right part of the e-mail address (after "@").
+ */
+ public String getDomain() {
+ return domain;
+ }
+
+ /**
+ * Returns the address in the form localPart@domain.
+ *
+ * @return the address part of this mailbox.
+ */
+ public String getAddress() {
+ if (domain == null) {
+ return localPart;
+ } else {
+ return localPart + '@' + domain;
+ }
+ }
+
+ @Override
+ protected final void doAddMailboxesTo(List results) {
+ results.add(this);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = LangUtils.HASH_SEED;
+ hash = LangUtils.hashCode(hash, this.localPart);
+ hash = LangUtils.hashCode(hash, this.domain != null ?
+ this.domain.toLowerCase(Locale.US) : null);
+ return hash;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this mailbox.
+ *
+ * An object is considered to be equal to this mailbox if it is an instance
+ * of class Mailbox
that holds the same address as this one.
+ * The domain is considered to be case-insensitive but the local-part is not
+ * (because of RFC 5321: the local-part of a mailbox MUST BE treated
+ * as case sensitive).
+ *
+ * @param obj
+ * the object to test for equality.
+ * @return true
if the specified object is a
+ * Mailbox
that holds the same address as this one.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+ if (!(obj instanceof Mailbox))
+ return false;
+ Mailbox that = (Mailbox) obj;
+ return LangUtils.equals(this.localPart, that.localPart) &&
+ LangUtils.equalsIgnoreCase(this.domain, that.domain);
+ }
+
+ @Override
+ public String toString() {
+ return getAddress();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/address/MailboxList.java b/src/org/apache/james/mime4j/dom/address/MailboxList.java
similarity index 53%
rename from src/org/apache/james/mime4j/field/address/MailboxList.java
rename to src/org/apache/james/mime4j/dom/address/MailboxList.java
index db814a7fe..da1b786c3 100644
--- a/src/org/apache/james/mime4j/field/address/MailboxList.java
+++ b/src/org/apache/james/mime4j/dom/address/MailboxList.java
@@ -17,55 +17,52 @@
* under the License. *
****************************************************************/
-package org.apache.james.mime4j.field.address;
+package org.apache.james.mime4j.dom.address;
+import java.io.Serializable;
+import java.util.AbstractList;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* An immutable, random-access list of Mailbox objects.
- *
- *
*/
-public class MailboxList {
+public class MailboxList extends AbstractList implements Serializable {
- private ArrayList mailboxes;
-
- /**
- * @param mailboxes An ArrayList that contains only Mailbox objects.
- * @param dontCopy true iff it is not possible for the mailboxes ArrayList to be modified by someone else.
- */
- public MailboxList(ArrayList mailboxes, boolean dontCopy) {
- if (mailboxes != null)
- this.mailboxes = (dontCopy ? mailboxes : (ArrayList) mailboxes.clone());
- else
- this.mailboxes = new ArrayList(0);
- }
-
- /**
- * The number of elements in this list.
- */
- public int size() {
- return mailboxes.size();
- }
-
- /**
- * Gets an address.
- */
- public Mailbox get(int index) {
- if (0 > index || size() <= index)
- throw new IndexOutOfBoundsException();
- return (Mailbox) mailboxes.get(index);
- }
-
- /**
- * Dumps a representation of this mailbox list to
- * stdout, for debugging purposes.
- */
- public void print() {
- for (int i = 0; i < size(); i++) {
- Mailbox mailbox = get(i);
- System.out.println(mailbox.toString());
- }
- }
+ private static final long serialVersionUID = 1L;
+
+ private final List mailboxes;
+
+ /**
+ * @param mailboxes
+ * A List that contains only Mailbox objects.
+ * @param dontCopy
+ * true iff it is not possible for the mailboxes list to be
+ * modified by someone else.
+ */
+ public MailboxList(List mailboxes, boolean dontCopy) {
+ if (mailboxes != null)
+ this.mailboxes = dontCopy ? mailboxes : new ArrayList(
+ mailboxes);
+ else
+ this.mailboxes = Collections.emptyList();
+ }
+
+ /**
+ * The number of elements in this list.
+ */
+ @Override
+ public int size() {
+ return mailboxes.size();
+ }
+
+ /**
+ * Gets an address.
+ */
+ @Override
+ public Mailbox get(int index) {
+ return mailboxes.get(index);
+ }
}
diff --git a/src/org/apache/james/mime4j/field/datetime/DateTime.java b/src/org/apache/james/mime4j/dom/datetime/DateTime.java
similarity index 67%
rename from src/org/apache/james/mime4j/field/datetime/DateTime.java
rename to src/org/apache/james/mime4j/dom/datetime/DateTime.java
index 506ff54e5..d19ab8c78 100644
--- a/src/org/apache/james/mime4j/field/datetime/DateTime.java
+++ b/src/org/apache/james/mime4j/dom/datetime/DateTime.java
@@ -17,17 +17,12 @@
* under the License. *
****************************************************************/
-package org.apache.james.mime4j.field.datetime;
+package org.apache.james.mime4j.dom.datetime;
-import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
-import org.apache.james.mime4j.field.datetime.parser.ParseException;
-import org.apache.james.mime4j.field.datetime.parser.TokenMgrError;
-
-import java.util.Date;
import java.util.Calendar;
-import java.util.TimeZone;
+import java.util.Date;
import java.util.GregorianCalendar;
-import java.io.StringReader;
+import java.util.TimeZone;
public class DateTime {
private final Date date;
@@ -112,16 +107,59 @@ public class DateTime {
}
public void print() {
- System.out.println(getYear() + " " + getMonth() + " " + getDay() + "; " + getHour() + " " + getMinute() + " " + getSecond() + " " + getTimeZone());
+ System.out.println(toString());
+ }
+
+ @Override
+ public String toString() {
+ return getYear() + " " + getMonth() + " " + getDay() + "; " + getHour() + " " + getMinute() + " " + getSecond() + " " + getTimeZone();
+ }
+
+ @Override
+ public int hashCode() {
+ final int PRIME = 31;
+ int result = 1;
+ result = PRIME * result + ((date == null) ? 0 : date.hashCode());
+ result = PRIME * result + day;
+ result = PRIME * result + hour;
+ result = PRIME * result + minute;
+ result = PRIME * result + month;
+ result = PRIME * result + second;
+ result = PRIME * result + timeZone;
+ result = PRIME * result + year;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final DateTime other = (DateTime) obj;
+ if (date == null) {
+ if (other.date != null)
+ return false;
+ } else if (!date.equals(other.date))
+ return false;
+ if (day != other.day)
+ return false;
+ if (hour != other.hour)
+ return false;
+ if (minute != other.minute)
+ return false;
+ if (month != other.month)
+ return false;
+ if (second != other.second)
+ return false;
+ if (timeZone != other.timeZone)
+ return false;
+ if (year != other.year)
+ return false;
+ return true;
}
- public static DateTime parse(String dateString) throws ParseException {
- try {
- return new DateTimeParser(new StringReader(dateString)).parseAll();
- }
- catch (TokenMgrError err) {
- throw new ParseException(err.getMessage());
- }
- }
}
diff --git a/src/org/apache/james/mime4j/dom/field/AddressListField.java b/src/org/apache/james/mime4j/dom/field/AddressListField.java
new file mode 100644
index 000000000..f8d2f0a99
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/AddressListField.java
@@ -0,0 +1,28 @@
+/****************************************************************
+ * 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.dom.field;
+
+import org.apache.james.mime4j.dom.address.AddressList;
+
+public interface AddressListField extends ParsedField {
+
+ AddressList getAddressList();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/ContentDispositionField.java b/src/org/apache/james/mime4j/dom/field/ContentDispositionField.java
new file mode 100644
index 000000000..10f984e6e
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/ContentDispositionField.java
@@ -0,0 +1,117 @@
+package org.apache.james.mime4j.dom.field;
+
+import java.util.Date;
+import java.util.Map;
+
+public interface ContentDispositionField extends ParsedField {
+
+ /** The inline
disposition type. */
+ public static final String DISPOSITION_TYPE_INLINE = "inline";
+ /** The attachment
disposition type. */
+ public static final String DISPOSITION_TYPE_ATTACHMENT = "attachment";
+ /** The name of the filename
parameter. */
+ public static final String PARAM_FILENAME = "filename";
+ /** The name of the creation-date
parameter. */
+ public static final String PARAM_CREATION_DATE = "creation-date";
+ /** The name of the modification-date
parameter. */
+ public static final String PARAM_MODIFICATION_DATE = "modification-date";
+ /** The name of the read-date
parameter. */
+ public static final String PARAM_READ_DATE = "read-date";
+ /** The name of the size
parameter. */
+ public static final String PARAM_SIZE = "size";
+
+ /**
+ * Gets the disposition type defined in this Content-Disposition field.
+ *
+ * @return the disposition type or an empty string if not set.
+ */
+ String getDispositionType();
+
+ /**
+ * Gets the value of a parameter. Parameter names are case-insensitive.
+ *
+ * @param name
+ * the name of the parameter to get.
+ * @return the parameter value or null
if not set.
+ */
+ String getParameter(String name);
+
+ /**
+ * Gets all parameters.
+ *
+ * @return the parameters.
+ */
+ Map getParameters();
+
+ /**
+ * Determines if the disposition type of this field matches the given one.
+ *
+ * @param dispositionType
+ * the disposition type to match against.
+ * @return true
if the disposition type of this field
+ * matches, false
otherwise.
+ */
+ boolean isDispositionType(String dispositionType);
+
+ /**
+ * Return true
if the disposition type of this field is
+ * inline, false
otherwise.
+ *
+ * @return true
if the disposition type of this field is
+ * inline, false
otherwise.
+ */
+ boolean isInline();
+
+ /**
+ * Return true
if the disposition type of this field is
+ * attachment, false
otherwise.
+ *
+ * @return true
if the disposition type of this field is
+ * attachment, false
otherwise.
+ */
+ public abstract boolean isAttachment();
+
+ /**
+ * Gets the value of the filename
parameter if set.
+ *
+ * @return the filename
parameter value or null
+ * if not set.
+ */
+ String getFilename();
+
+ /**
+ * Gets the value of the creation-date
parameter if set and
+ * valid.
+ *
+ * @return the creation-date
parameter value or
+ * null
if not set or invalid.
+ */
+ Date getCreationDate();
+
+ /**
+ * Gets the value of the modification-date
parameter if set
+ * and valid.
+ *
+ * @return the modification-date
parameter value or
+ * null
if not set or invalid.
+ */
+ Date getModificationDate();
+
+ /**
+ * Gets the value of the read-date
parameter if set and
+ * valid.
+ *
+ * @return the read-date
parameter value or null
+ * if not set or invalid.
+ */
+ Date getReadDate();
+
+ /**
+ * Gets the value of the size
parameter if set and valid.
+ *
+ * @return the size
parameter value or -1
if
+ * not set or invalid.
+ */
+ long getSize();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/ContentTransferEncodingField.java b/src/org/apache/james/mime4j/dom/field/ContentTransferEncodingField.java
new file mode 100644
index 000000000..994f1e1ad
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/ContentTransferEncodingField.java
@@ -0,0 +1,31 @@
+/****************************************************************
+ * 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.dom.field;
+
+public interface ContentTransferEncodingField extends ParsedField {
+
+ /**
+ * Gets the encoding defined in this field.
+ *
+ * @return the encoding or an empty string if not set.
+ */
+ String getEncoding();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/ContentTypeField.java b/src/org/apache/james/mime4j/dom/field/ContentTypeField.java
new file mode 100644
index 000000000..467a24ce3
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/ContentTypeField.java
@@ -0,0 +1,97 @@
+/****************************************************************
+ * 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.dom.field;
+
+import java.util.Map;
+
+public interface ContentTypeField extends ParsedField {
+
+ /** The prefix of all multipart
MIME types. */
+ public static final String TYPE_MULTIPART_PREFIX = "multipart/";
+ /** The multipart/digest
MIME type. */
+ public static final String TYPE_MULTIPART_DIGEST = "multipart/digest";
+ /** The text/plain
MIME type. */
+ public static final String TYPE_TEXT_PLAIN = "text/plain";
+ /** The message/rfc822
MIME type. */
+ public static final String TYPE_MESSAGE_RFC822 = "message/rfc822";
+ /** The name of the boundary
parameter. */
+ public static final String PARAM_BOUNDARY = "boundary";
+ /** The name of the charset
parameter. */
+ public static final String PARAM_CHARSET = "charset";
+
+ /**
+ * Gets the MIME type defined in this Content-Type field.
+ *
+ * @return the MIME type or an empty string if not set.
+ */
+ String getMimeType();
+
+ /**
+ * Gets the value of a parameter. Parameter names are case-insensitive.
+ *
+ * @param name
+ * the name of the parameter to get.
+ * @return the parameter value or null
if not set.
+ */
+ String getParameter(String name);
+
+ /**
+ * Gets all parameters.
+ *
+ * @return the parameters.
+ */
+ Map getParameters();
+
+ /**
+ * Determines if the MIME type of this field matches the given one.
+ *
+ * @param mimeType
+ * the MIME type to match against.
+ * @return true
if the MIME type of this field matches,
+ * false
otherwise.
+ */
+ boolean isMimeType(String mimeType);
+
+ /**
+ * Determines if the MIME type of this field is multipart/*
.
+ *
+ * @return true
if this field is has a
+ * multipart/*
MIME type, false
+ * otherwise.
+ */
+ boolean isMultipart();
+
+ /**
+ * Gets the value of the boundary
parameter if set.
+ *
+ * @return the boundary
parameter value or null
+ * if not set.
+ */
+ String getBoundary();
+
+ /**
+ * Gets the value of the charset
parameter if set.
+ *
+ * @return the charset
parameter value or null
+ * if not set.
+ */
+ String getCharset();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/DateTimeField.java b/src/org/apache/james/mime4j/dom/field/DateTimeField.java
new file mode 100644
index 000000000..ce0282db9
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/DateTimeField.java
@@ -0,0 +1,9 @@
+package org.apache.james.mime4j.dom.field;
+
+import java.util.Date;
+
+public interface DateTimeField extends ParsedField {
+
+ Date getDate();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/Field.java b/src/org/apache/james/mime4j/dom/field/Field.java
new file mode 100644
index 000000000..f9db369f9
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/Field.java
@@ -0,0 +1,51 @@
+/****************************************************************
+ * 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.dom.field;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Abstract MIME field.
+ */
+public interface Field {
+
+ /**
+ * Gets the name of the field (Subject
, From
, etc).
+ *
+ * @return the field name.
+ */
+ String getName();
+
+ /**
+ * Gets the unparsed and possibly encoded (see RFC 2047) field body string.
+ *
+ * @return the unparsed field body string.
+ */
+ String getBody();
+
+ /**
+ * Writes the original raw field bytes to an output stream.
+ * The output is folded, the last CRLF is not included.
+ * @throws IOException
+ */
+ void writeTo(OutputStream out) throws IOException;
+
+}
diff --git a/src/org/apache/james/mime4j/decoder/ByteQueue.java b/src/org/apache/james/mime4j/dom/field/FieldName.java
similarity index 50%
rename from src/org/apache/james/mime4j/decoder/ByteQueue.java
rename to src/org/apache/james/mime4j/dom/field/FieldName.java
index 6d7ccef52..d9ab42fa6 100644
--- a/src/org/apache/james/mime4j/decoder/ByteQueue.java
+++ b/src/org/apache/james/mime4j/dom/field/FieldName.java
@@ -17,46 +17,37 @@
* under the License. *
****************************************************************/
-package org.apache.james.mime4j.decoder;
+package org.apache.james.mime4j.dom.field;
-import java.util.Iterator;
+/**
+ * Constants for common header field names.
+ */
+public class FieldName {
-public class ByteQueue {
+ public static final String CONTENT_DISPOSITION = "Content-Disposition";
+ public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+ public static final String CONTENT_TYPE = "Content-Type";
- private UnboundedFifoByteBuffer buf;
- private int initialCapacity = -1;
+ public static final String DATE = "Date";
+ public static final String MESSAGE_ID = "Message-ID";
+ public static final String SUBJECT = "Subject";
- public ByteQueue() {
- buf = new UnboundedFifoByteBuffer();
+ public static final String FROM = "From";
+ public static final String SENDER = "Sender";
+ public static final String TO = "To";
+ public static final String CC = "Cc";
+ public static final String BCC = "Bcc";
+ public static final String REPLY_TO = "Reply-To";
+
+ public static final String RESENT_DATE = "Resent-Date";
+
+ public static final String RESENT_FROM = "Resent-From";
+ public static final String RESENT_SENDER = "Resent-Sender";
+ public static final String RESENT_TO = "Resent-To";
+ public static final String RESENT_CC = "Resent-Cc";
+ public static final String RESENT_BCC = "Resent-Bcc";
+
+ private FieldName() {
}
- public ByteQueue(int initialCapacity) {
- buf = new UnboundedFifoByteBuffer(initialCapacity);
- this.initialCapacity = initialCapacity;
- }
-
- public void enqueue(byte b) {
- buf.add(b);
- }
-
- public byte dequeue() {
- return buf.remove();
- }
-
- public int count() {
- return buf.size();
- }
-
- public void clear() {
- if (initialCapacity != -1)
- buf = new UnboundedFifoByteBuffer(initialCapacity);
- else
- buf = new UnboundedFifoByteBuffer();
- }
-
- public Iterator iterator() {
- return buf.iterator();
- }
-
-
}
diff --git a/src/org/apache/james/mime4j/dom/field/MailboxField.java b/src/org/apache/james/mime4j/dom/field/MailboxField.java
new file mode 100644
index 000000000..64c3fa338
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/MailboxField.java
@@ -0,0 +1,28 @@
+/****************************************************************
+ * 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.dom.field;
+
+import org.apache.james.mime4j.dom.address.Mailbox;
+
+public interface MailboxField extends ParsedField {
+
+ Mailbox getMailbox();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/MailboxListField.java b/src/org/apache/james/mime4j/dom/field/MailboxListField.java
new file mode 100644
index 000000000..e02bdd89a
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/MailboxListField.java
@@ -0,0 +1,28 @@
+/****************************************************************
+ * 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.dom.field;
+
+import org.apache.james.mime4j.dom.address.MailboxList;
+
+public interface MailboxListField extends ParsedField {
+
+ MailboxList getMailboxList();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/dom/field/ParseException.java b/src/org/apache/james/mime4j/dom/field/ParseException.java
new file mode 100644
index 000000000..e4baf77b3
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/ParseException.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.dom.field;
+
+import org.apache.james.mime4j.MimeException;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ */
+public class ParseException extends MimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a new parse exception with the specified detail message.
+ *
+ * @param message
+ * detail message
+ */
+ protected ParseException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new parse exception with the specified cause.
+ *
+ * @param cause
+ * the cause
+ */
+ protected ParseException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a new parse exception with the specified detail message and
+ * cause.
+ *
+ * @param message
+ * detail message
+ * @param cause
+ * the cause
+ */
+ protected ParseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/dom/field/ParsedField.java b/src/org/apache/james/mime4j/dom/field/ParsedField.java
new file mode 100644
index 000000000..4f91e2717
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/ParsedField.java
@@ -0,0 +1,45 @@
+/****************************************************************
+ * 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.dom.field;
+
+
+public interface ParsedField extends Field {
+
+ /**
+ * Returns true
if this field is valid, i.e. no errors were
+ * encountered while parsing the field value.
+ *
+ * @return true
if this field is valid, false
+ * otherwise.
+ * @see #getParseException()
+ */
+ boolean isValidField();
+
+ /**
+ * Returns the exception that was thrown by the field parser while parsing
+ * the field value. The result is null
if the field is valid
+ * and no errors were encountered.
+ *
+ * @return the exception that was thrown by the field parser or
+ * null
if the field is valid.
+ */
+ ParseException getParseException();
+
+}
diff --git a/src/org/apache/james/mime4j/dom/field/UnstructuredField.java b/src/org/apache/james/mime4j/dom/field/UnstructuredField.java
new file mode 100644
index 000000000..6651e2deb
--- /dev/null
+++ b/src/org/apache/james/mime4j/dom/field/UnstructuredField.java
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.dom.field;
+
+public interface UnstructuredField extends ParsedField {
+
+ String getValue();
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/field/AbstractField.java b/src/org/apache/james/mime4j/field/AbstractField.java
new file mode 100644
index 000000000..21939a11e
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/AbstractField.java
@@ -0,0 +1,97 @@
+/****************************************************************
+ * 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 java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.field.ParseException;
+import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * The base class of all field classes.
+ */
+public abstract class AbstractField implements ParsedField {
+
+ private final String name;
+ private final String body;
+ private final ByteSequence raw;
+ protected DecodeMonitor monitor;
+
+ protected AbstractField(
+ final String name,
+ final String body,
+ final ByteSequence raw,
+ final DecodeMonitor monitor) {
+ this.name = name;
+ this.body = body;
+ this.raw = raw;
+ this.monitor = monitor != null ? monitor : DecodeMonitor.SILENT;
+ }
+
+ /**
+ * Gets the name of the field (Subject
,
+ * From
, etc).
+ *
+ * @return the field name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.Field#writeTo(java.io.OutputStream)
+ */
+ public void writeTo(OutputStream out) throws IOException {
+ out.write(raw.toByteArray());
+ }
+
+ /**
+ * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field
+ * body string.
+ *
+ * @return the unfolded unparsed field body string.
+ */
+ public String getBody() {
+ return body;
+ }
+
+ /**
+ * @see ParsedField#isValidField()
+ */
+ public boolean isValidField() {
+ return getParseException() == null;
+ }
+
+ /**
+ * @see ParsedField#getParseException()
+ */
+ public ParseException getParseException() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return name + ": " + body;
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/AddressListField.java b/src/org/apache/james/mime4j/field/AddressListFieldImpl.java
similarity index 51%
rename from src/org/apache/james/mime4j/field/AddressListField.java
rename to src/org/apache/james/mime4j/field/AddressListFieldImpl.java
index a2e6f992f..a5395bc1c 100644
--- a/src/org/apache/james/mime4j/field/AddressListField.java
+++ b/src/org/apache/james/mime4j/field/AddressListFieldImpl.java
@@ -19,45 +19,63 @@
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.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.field.address.parser.AddressBuilder;
import org.apache.james.mime4j.field.address.parser.ParseException;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Address list field such as To
or Reply-To
.
+ */
+public class AddressListFieldImpl extends AbstractField implements org.apache.james.mime4j.dom.field.AddressListField {
+
+ private boolean parsed = false;
-public class AddressListField extends Field {
private AddressList addressList;
private ParseException parseException;
- protected AddressListField(String name, String body, String raw, AddressList addressList, ParseException parseException) {
- super(name, body, raw);
- this.addressList = addressList;
- this.parseException = parseException;
+ AddressListFieldImpl(String name, String body, ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
}
+ /**
+ * @see org.apache.james.mime4j.dom.field.AddressListField#getAddressList()
+ */
public AddressList getAddressList() {
+ if (!parsed)
+ parse();
+
return addressList;
}
+ /**
+ * @see org.apache.james.mime4j.dom.field.AddressListField#getParseException()
+ */
+ @Override
public ParseException getParseException() {
+ if (!parsed)
+ parse();
+
return parseException;
}
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
+ private void parse() {
+ String body = getBody();
- public Field parse(final String name, final String body, final String raw) {
- AddressList addressList = null;
- ParseException parseException = null;
- try {
- addressList = AddressList.parse(body);
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new AddressListField(name, body, raw, addressList, parseException);
+ try {
+ addressList = AddressBuilder.parseAddressList(body, monitor);
+ } catch (ParseException e) {
+ parseException = e;
}
+
+ parsed = true;
}
+
+ static final FieldParser PARSER = new FieldParser() {
+ public AddressListFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new AddressListFieldImpl(name, body, raw, monitor);
+ }
+ };
}
diff --git a/src/org/apache/james/mime4j/field/ContentDispositionFieldImpl.java b/src/org/apache/james/mime4j/field/ContentDispositionFieldImpl.java
new file mode 100644
index 000000000..81b26bd8d
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/ContentDispositionFieldImpl.java
@@ -0,0 +1,253 @@
+/****************************************************************
+ * 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 java.io.StringReader;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.field.contentdisposition.parser.ContentDispositionParser;
+import org.apache.james.mime4j.field.contentdisposition.parser.ParseException;
+import org.apache.james.mime4j.field.contentdisposition.parser.TokenMgrError;
+import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Represents a Content-Disposition
field.
+ */
+public class ContentDispositionFieldImpl extends AbstractField implements org.apache.james.mime4j.dom.field.ContentDispositionField {
+
+ private boolean parsed = false;
+
+ private String dispositionType = "";
+ private Map parameters = new HashMap();
+ private ParseException parseException;
+
+ private boolean creationDateParsed;
+ private Date creationDate;
+
+ private boolean modificationDateParsed;
+ private Date modificationDate;
+
+ private boolean readDateParsed;
+ private Date readDate;
+
+ ContentDispositionFieldImpl(String name, String body, ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
+ }
+
+ /**
+ * Gets the exception that was raised during parsing of the field value, if
+ * any; otherwise, null.
+ */
+ @Override
+ public ParseException getParseException() {
+ if (!parsed)
+ parse();
+
+ return parseException;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getDispositionType()
+ */
+ public String getDispositionType() {
+ if (!parsed)
+ parse();
+
+ return dispositionType;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getParameter(java.lang.String)
+ */
+ public String getParameter(String name) {
+ if (!parsed)
+ parse();
+
+ return parameters.get(name.toLowerCase());
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getParameters()
+ */
+ public Map getParameters() {
+ if (!parsed)
+ parse();
+
+ return Collections.unmodifiableMap(parameters);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#isDispositionType(java.lang.String)
+ */
+ public boolean isDispositionType(String dispositionType) {
+ if (!parsed)
+ parse();
+
+ return this.dispositionType.equalsIgnoreCase(dispositionType);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#isInline()
+ */
+ public boolean isInline() {
+ if (!parsed)
+ parse();
+
+ return dispositionType.equals(DISPOSITION_TYPE_INLINE);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#isAttachment()
+ */
+ public boolean isAttachment() {
+ if (!parsed)
+ parse();
+
+ return dispositionType.equals(DISPOSITION_TYPE_ATTACHMENT);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getFilename()
+ */
+ public String getFilename() {
+ return getParameter(PARAM_FILENAME);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getCreationDate()
+ */
+ public Date getCreationDate() {
+ if (!creationDateParsed) {
+ creationDate = parseDate(PARAM_CREATION_DATE);
+ creationDateParsed = true;
+ }
+
+ return creationDate;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getModificationDate()
+ */
+ public Date getModificationDate() {
+ if (!modificationDateParsed) {
+ modificationDate = parseDate(PARAM_MODIFICATION_DATE);
+ modificationDateParsed = true;
+ }
+
+ return modificationDate;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getReadDate()
+ */
+ public Date getReadDate() {
+ if (!readDateParsed) {
+ readDate = parseDate(PARAM_READ_DATE);
+ readDateParsed = true;
+ }
+
+ return readDate;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getSize()
+ */
+ public long getSize() {
+ String value = getParameter(PARAM_SIZE);
+ if (value == null)
+ return -1;
+
+ try {
+ long size = Long.parseLong(value);
+ return size < 0 ? -1 : size;
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
+ private Date parseDate(String paramName) {
+ String value = getParameter(paramName);
+ if (value == null) {
+ monitor.warn("Parsing " + paramName + " null", "returning null");
+ return null;
+ }
+
+ try {
+ return new DateTimeParser(new StringReader(value)).parseAll()
+ .getDate();
+ } catch (org.apache.james.mime4j.field.datetime.parser.ParseException e) {
+ monitor.warn("Parsing " + paramName + " '" + value + "': "
+ + e.getMessage(), "returning null");
+ return null;
+ } catch (org.apache.james.mime4j.field.datetime.parser.TokenMgrError e) {
+ monitor.warn("Parsing " + paramName + " '" + value + "': "
+ + e.getMessage(), "returning null");
+ return null;
+ }
+ }
+
+ private void parse() {
+ String body = getBody();
+
+ ContentDispositionParser parser = new ContentDispositionParser(
+ new StringReader(body));
+ try {
+ parser.parseAll();
+ } catch (ParseException e) {
+ parseException = e;
+ } catch (TokenMgrError e) {
+ parseException = new ParseException(e.getMessage());
+ }
+
+ final String dispositionType = parser.getDispositionType();
+
+ if (dispositionType != null) {
+ this.dispositionType = dispositionType.toLowerCase(Locale.US);
+
+ List paramNames = parser.getParamNames();
+ List paramValues = parser.getParamValues();
+
+ if (paramNames != null && paramValues != null) {
+ final int len = Math.min(paramNames.size(), paramValues.size());
+ for (int i = 0; i < len; i++) {
+ String paramName = paramNames.get(i).toLowerCase(Locale.US);
+ String paramValue = paramValues.get(i);
+ parameters.put(paramName, paramValue);
+ }
+ }
+ }
+
+ parsed = true;
+ }
+
+ static final FieldParser PARSER = new FieldParser() {
+ public ContentDispositionFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new ContentDispositionFieldImpl(name, body, raw, monitor);
+ }
+ };
+}
diff --git a/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java b/src/org/apache/james/mime4j/field/ContentTransferEncodingFieldImpl.java
similarity index 54%
rename from src/org/apache/james/mime4j/field/ContentTransferEncodingField.java
rename to src/org/apache/james/mime4j/field/ContentTransferEncodingFieldImpl.java
index 73d8d2339..c42220f61 100644
--- a/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java
+++ b/src/org/apache/james/mime4j/field/ContentTransferEncodingFieldImpl.java
@@ -19,70 +19,47 @@
package org.apache.james.mime4j.field;
-
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.MimeUtil;
/**
* Represents a Content-Transfer-Encoding
field.
- *
- *
- * @version $Id: ContentTransferEncodingField.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
*/
-public class ContentTransferEncodingField extends Field {
- /**
- * The 7bit
encoding.
- */
- public static final String ENC_7BIT = "7bit";
- /**
- * The 8bit
encoding.
- */
- public static final String ENC_8BIT = "8bit";
- /**
- * The binary
encoding.
- */
- public static final String ENC_BINARY = "binary";
- /**
- * The quoted-printable
encoding.
- */
- public static final String ENC_QUOTED_PRINTABLE = "quoted-printable";
- /**
- * The base64
encoding.
- */
- public static final String ENC_BASE64 = "base64";
-
+public class ContentTransferEncodingFieldImpl extends AbstractField implements ContentTransferEncodingField {
private String encoding;
-
- protected ContentTransferEncodingField(String name, String body, String raw, String encoding) {
- super(name, body, raw);
- this.encoding = encoding;
+
+ ContentTransferEncodingFieldImpl(String name, String body, ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
+ encoding = body.trim().toLowerCase();
}
/**
- * Gets the encoding defined in this field.
- *
- * @return the encoding or an empty string if not set.
+ * @see org.apache.james.mime4j.dom.field.ContentTransferEncodingField#getEncoding()
*/
public String getEncoding() {
return encoding;
}
-
+
/**
- * Gets the encoding of the given field if. Returns the default
- * 7bit
if not set or if
- * f
is null
.
- *
+ * Gets the encoding of the given field if. Returns the default
+ * 7bit
if not set or if f
is
+ * null
.
+ *
* @return the encoding.
*/
public static String getEncoding(ContentTransferEncodingField f) {
if (f != null && f.getEncoding().length() != 0) {
return f.getEncoding();
}
- return ENC_7BIT;
+ return MimeUtil.ENC_7BIT;
}
-
- public static class Parser implements FieldParser {
- public Field parse(final String name, final String body, final String raw) {
- final String encoding = body.trim().toLowerCase();
- return new ContentTransferEncodingField(name, body, raw, encoding);
+
+ static final FieldParser PARSER = new FieldParser() {
+ public ContentTransferEncodingFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new ContentTransferEncodingFieldImpl(name, body, raw, monitor);
}
- }
+ };
}
diff --git a/src/org/apache/james/mime4j/field/ContentTypeField.java b/src/org/apache/james/mime4j/field/ContentTypeField.java
deleted file mode 100644
index 01f640cce..000000000
--- a/src/org/apache/james/mime4j/field/ContentTypeField.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/****************************************************************
- * 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 java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Collections;
-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.field.contenttype.parser.ContentTypeParser;
-import org.apache.james.mime4j.field.contenttype.parser.ParseException;
-import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError;
-
-/**
- * Represents a Content-Type
field.
- *
- * TODO: Remove dependency on Java 1.4 regexps
- *
- *
- * @version $Id: ContentTypeField.java,v 1.6 2005/01/27 14:16:31 ntherning Exp $
- */
-public class ContentTypeField extends Field {
-
- /**
- * The prefix of all multipart
MIME types.
- */
- public static final String TYPE_MULTIPART_PREFIX = "multipart/";
- /**
- * The multipart/digest
MIME type.
- */
- public static final String TYPE_MULTIPART_DIGEST = "multipart/digest";
- /**
- * The text/plain
MIME type.
- */
- public static final String TYPE_TEXT_PLAIN = "text/plain";
- /**
- * The message/rfc822
MIME type.
- */
- public static final String TYPE_MESSAGE_RFC822 = "message/rfc822";
- /**
- * The name of the boundary
parameter.
- */
- public static final String PARAM_BOUNDARY = "boundary";
- /**
- * The name of the charset
parameter.
- */
- public static final String PARAM_CHARSET = "charset";
-
- private String mimeType = "";
- private Map parameters = null;
- private ParseException parseException;
-
- protected ContentTypeField(String name, String body, String raw, String mimeType, Map parameters, ParseException parseException) {
- super(name, body, raw);
- this.mimeType = mimeType;
- this.parameters = parameters;
- this.parseException = parseException;
- }
-
- /**
- * Gets the exception that was raised during parsing of
- * the field value, if any; otherwise, null.
- */
- public ParseException getParseException() {
- return parseException;
- }
-
- /**
- * Gets the MIME type defined in this Content-Type field.
- *
- * @return the MIME type or an empty string if not set.
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Gets the MIME type defined in the child's
- * Content-Type field or derives a MIME type from the parent
- * if child is null
or hasn't got a MIME type value set.
- * If child's MIME type is multipart but no boundary
- * has been set the MIME type of child will be derived from
- * the parent.
- *
- * @param child the child.
- * @param parent the parent.
- * @return the MIME type.
- */
- public static String getMimeType(ContentTypeField child,
- ContentTypeField parent) {
-
- if (child == null || child.getMimeType().length() == 0
- || child.isMultipart() && child.getBoundary() == null) {
-
- if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) {
- return TYPE_MESSAGE_RFC822;
- } else {
- return TYPE_TEXT_PLAIN;
- }
- }
-
- return child.getMimeType();
- }
-
- /**
- * Gets the value of a parameter. Parameter names are case-insensitive.
- *
- * @param name the name of the parameter to get.
- * @return the parameter value or null
if not set.
- */
- public String getParameter(String name) {
- return parameters != null
- ? (String) parameters.get(name.toLowerCase())
- : null;
- }
-
- /**
- * Gets all parameters.
- *
- * @return the parameters.
- */
- public Map getParameters() {
- return parameters != null
- ? Collections.unmodifiableMap(parameters)
- : Collections.EMPTY_MAP;
- }
-
- /**
- * Gets the value of the boundary
parameter if set.
- *
- * @return the boundary
parameter value or null
- * if not set.
- */
- public String getBoundary() {
- return getParameter(PARAM_BOUNDARY);
- }
-
- /**
- * Gets the value of the charset
parameter if set.
- *
- * @return the charset
parameter value or null
- * if not set.
- */
- public String getCharset() {
- return getParameter(PARAM_CHARSET);
- }
-
- /**
- * Gets the value of the charset
parameter if set for the
- * given field. Returns the default us-ascii
if not set or if
- * f
is null
.
- *
- * @return the charset
parameter value.
- */
- public static String getCharset(ContentTypeField f) {
- if (f != null) {
- if (f.getCharset() != null && f.getCharset().length() > 0) {
- return f.getCharset();
- }
- }
- return "us-ascii";
- }
-
- /**
- * Determines if the MIME type of this field matches the given one.
- *
- * @param mimeType the MIME type to match against.
- * @return true
if the MIME type of this field matches,
- * false
otherwise.
- */
- public boolean isMimeType(String mimeType) {
- return this.mimeType.equalsIgnoreCase(mimeType);
- }
-
- /**
- * Determines if the MIME type of this field is multipart/*
.
- *
- * @return true
if this field is has a multipart/*
- * MIME type, false
otherwise.
- */
- public boolean isMultipart() {
- return mimeType.startsWith(TYPE_MULTIPART_PREFIX);
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- ParseException parseException = null;
- String mimeType = "";
- Map parameters = null;
-
- ContentTypeParser parser = new ContentTypeParser(new StringReader(body));
- try {
- parser.parseAll();
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- catch (TokenMgrError e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = new ParseException(e.getMessage());
- }
-
- try {
- final String type = parser.getType();
- final String subType = parser.getSubType();
-
- if (type != null && subType != null) {
- mimeType = (type + "/" + parser.getSubType()).toLowerCase();
-
- ArrayList paramNames = parser.getParamNames();
- ArrayList paramValues = parser.getParamValues();
-
- if (paramNames != null && paramValues != null) {
- for (int i = 0; i < paramNames.size() && i < paramValues.size(); i++) {
- if (parameters == null)
- parameters = new HashMap((int)(paramNames.size() * 1.3 + 1));
- String paramName = ((String)paramNames.get(i)).toLowerCase();
- String paramValue = ((String)paramValues.get(i));
- parameters.put(paramName, paramValue);
- }
- }
- }
- }
- catch (NullPointerException npe) {
- }
- return new ContentTypeField(name, body, raw, mimeType, parameters, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/ContentTypeFieldImpl.java b/src/org/apache/james/mime4j/field/ContentTypeFieldImpl.java
new file mode 100644
index 000000000..2454a4d84
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/ContentTypeFieldImpl.java
@@ -0,0 +1,208 @@
+/****************************************************************
+ * 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 java.io.StringReader;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.field.ContentTypeField;
+import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser;
+import org.apache.james.mime4j.field.contenttype.parser.ParseException;
+import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Represents a Content-Type
field.
+ */
+public class ContentTypeFieldImpl extends AbstractField implements ContentTypeField {
+ private boolean parsed = false;
+
+ private String mimeType = "";
+ private Map parameters = new HashMap();
+ private ParseException parseException;
+
+ ContentTypeFieldImpl(String name, String body, ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#getParseException()
+ */
+ @Override
+ public ParseException getParseException() {
+ if (!parsed)
+ parse();
+
+ return parseException;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#getMimeType()
+ */
+ public String getMimeType() {
+ if (!parsed)
+ parse();
+
+ return mimeType;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#getParameter(java.lang.String)
+ */
+ public String getParameter(String name) {
+ if (!parsed)
+ parse();
+
+ return parameters.get(name.toLowerCase());
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#getParameters()
+ */
+ public Map getParameters() {
+ if (!parsed)
+ parse();
+
+ return Collections.unmodifiableMap(parameters);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#isMimeType(java.lang.String)
+ */
+ public boolean isMimeType(String mimeType) {
+ if (!parsed)
+ parse();
+
+ return this.mimeType.equalsIgnoreCase(mimeType);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#isMultipart()
+ */
+ public boolean isMultipart() {
+ if (!parsed)
+ parse();
+
+ return mimeType.startsWith(TYPE_MULTIPART_PREFIX);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#getBoundary()
+ */
+ public String getBoundary() {
+ return getParameter(PARAM_BOUNDARY);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.ContentTypeField#getCharset()
+ */
+ public String getCharset() {
+ return getParameter(PARAM_CHARSET);
+ }
+
+ /**
+ * Gets the MIME type defined in the child's Content-Type field or derives a
+ * MIME type from the parent if child is null
or hasn't got a
+ * MIME type value set. If child's MIME type is multipart but no boundary
+ * has been set the MIME type of child will be derived from the parent.
+ *
+ * @param child
+ * the child.
+ * @param parent
+ * the parent.
+ * @return the MIME type.
+ */
+ public static String getMimeType(ContentTypeField child,
+ ContentTypeField parent) {
+ if (child == null || child.getMimeType().length() == 0
+ || child.isMultipart() && child.getBoundary() == null) {
+
+ if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) {
+ return TYPE_MESSAGE_RFC822;
+ } else {
+ return TYPE_TEXT_PLAIN;
+ }
+ }
+
+ return child.getMimeType();
+ }
+
+ /**
+ * Gets the value of the charset
parameter if set for the
+ * given field. Returns the default us-ascii
if not set or if
+ * f
is null
.
+ *
+ * @return the charset
parameter value.
+ */
+ public static String getCharset(ContentTypeField f) {
+ if (f != null) {
+ String charset = f.getCharset();
+ if (charset != null && charset.length() > 0) {
+ return charset;
+ }
+ }
+ return "us-ascii";
+ }
+
+ private void parse() {
+ String body = getBody();
+
+ ContentTypeParser parser = new ContentTypeParser(new StringReader(body));
+ try {
+ parser.parseAll();
+ } catch (ParseException e) {
+ parseException = e;
+ } catch (TokenMgrError e) {
+ parseException = new ParseException(e.getMessage());
+ }
+
+ final String type = parser.getType();
+ final String subType = parser.getSubType();
+
+ if (type != null && subType != null) {
+ mimeType = (type + "/" + subType).toLowerCase();
+
+ List paramNames = parser.getParamNames();
+ List paramValues = parser.getParamValues();
+
+ if (paramNames != null && paramValues != null) {
+ final int len = Math.min(paramNames.size(), paramValues.size());
+ for (int i = 0; i < len; i++) {
+ String paramName = paramNames.get(i).toLowerCase();
+ String paramValue = paramValues.get(i);
+ parameters.put(paramName, paramValue);
+ }
+ }
+ }
+
+ parsed = true;
+ }
+
+ static final FieldParser PARSER = new FieldParser() {
+ public ContentTypeFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new ContentTypeFieldImpl(name, body, raw, monitor);
+ }
+ };
+}
diff --git a/src/org/apache/james/mime4j/field/DateTimeField.java b/src/org/apache/james/mime4j/field/DateTimeField.java
deleted file mode 100644
index fa34ceda4..000000000
--- a/src/org/apache/james/mime4j/field/DateTimeField.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************
- * 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.datetime.DateTime;
-import org.apache.james.mime4j.field.datetime.parser.ParseException;
-
-import java.util.Date;
-
-public class DateTimeField extends Field {
- private Date date;
- private ParseException parseException;
-
- protected DateTimeField(String name, String body, String raw, Date date, ParseException parseException) {
- super(name, body, raw);
- this.date = date;
- this.parseException = parseException;
- }
-
- public Date getDate() {
- return date;
- }
-
- public ParseException getParseException() {
- return parseException;
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- Date date = null;
- ParseException parseException = null;
- try {
- date = DateTime.parse(body).getDate();
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new DateTimeField(name, body, raw, date, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/DateTimeFieldImpl.java b/src/org/apache/james/mime4j/field/DateTimeFieldImpl.java
new file mode 100644
index 000000000..f223899d1
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/DateTimeFieldImpl.java
@@ -0,0 +1,86 @@
+/****************************************************************
+ * 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 java.io.StringReader;
+import java.util.Date;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
+import org.apache.james.mime4j.field.datetime.parser.ParseException;
+import org.apache.james.mime4j.field.datetime.parser.TokenMgrError;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Date-time field such as Date
or Resent-Date
.
+ */
+public class DateTimeFieldImpl extends AbstractField implements org.apache.james.mime4j.dom.field.DateTimeField {
+ private boolean parsed = false;
+
+ private Date date;
+ private ParseException parseException;
+
+ DateTimeFieldImpl(String name, String body, ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.DateTimeField#getDate()
+ */
+ public Date getDate() {
+ if (!parsed)
+ parse();
+
+ return date;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.DateTimeField#getParseException()
+ */
+ @Override
+ public ParseException getParseException() {
+ if (!parsed)
+ parse();
+
+ return parseException;
+ }
+
+ private void parse() {
+ String body = getBody();
+
+ try {
+ date = new DateTimeParser(new StringReader(body)).parseAll()
+ .getDate();
+ } catch (ParseException e) {
+ parseException = e;
+ } catch (TokenMgrError e) {
+ parseException = new ParseException(e.getMessage());
+ }
+
+ parsed = true;
+ }
+
+ static final FieldParser PARSER = new FieldParser() {
+ public DateTimeFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new DateTimeFieldImpl(name, body, raw, monitor);
+ }
+ };
+}
diff --git a/src/org/apache/james/mime4j/field/DefaultFieldParser.java b/src/org/apache/james/mime4j/field/DefaultFieldParser.java
index 3695afe3e..befa6bd64 100644
--- a/src/org/apache/james/mime4j/field/DefaultFieldParser.java
+++ b/src/org/apache/james/mime4j/field/DefaultFieldParser.java
@@ -1,45 +1,133 @@
-/*
- * Copyright 2006 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.field.FieldName;
+import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.field.AddressListFieldImpl;
+import org.apache.james.mime4j.field.ContentDispositionFieldImpl;
+import org.apache.james.mime4j.field.ContentTransferEncodingFieldImpl;
+import org.apache.james.mime4j.field.ContentTypeFieldImpl;
+import org.apache.james.mime4j.field.DateTimeFieldImpl;
+import org.apache.james.mime4j.field.MailboxFieldImpl;
+import org.apache.james.mime4j.field.MailboxListFieldImpl;
+import org.apache.james.mime4j.field.UnstructuredFieldImpl;
+import org.apache.james.mime4j.stream.RawField;
+import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
+
public class DefaultFieldParser extends DelegatingFieldParser {
+
+ private static final DefaultFieldParser PARSER = new DefaultFieldParser();
- public DefaultFieldParser() {
- setFieldParser(Field.CONTENT_TRANSFER_ENCODING, new ContentTransferEncodingField.Parser());
- setFieldParser(Field.CONTENT_TYPE, new ContentTypeField.Parser());
-
- final DateTimeField.Parser dateTimeParser = new DateTimeField.Parser();
- setFieldParser(Field.DATE, dateTimeParser);
- setFieldParser(Field.RESENT_DATE, dateTimeParser);
-
- final MailboxListField.Parser mailboxListParser = new MailboxListField.Parser();
- setFieldParser(Field.FROM, mailboxListParser);
- setFieldParser(Field.RESENT_FROM, mailboxListParser);
-
- final MailboxField.Parser mailboxParser = new MailboxField.Parser();
- setFieldParser(Field.SENDER, mailboxParser);
- setFieldParser(Field.RESENT_SENDER, mailboxParser);
-
- final AddressListField.Parser addressListParser = new AddressListField.Parser();
- setFieldParser(Field.TO, addressListParser);
- setFieldParser(Field.RESENT_TO, addressListParser);
- setFieldParser(Field.CC, addressListParser);
- setFieldParser(Field.RESENT_CC, addressListParser);
- setFieldParser(Field.BCC, addressListParser);
- setFieldParser(Field.RESENT_BCC, addressListParser);
- setFieldParser(Field.REPLY_TO, addressListParser);
+
+ /**
+ * Gets the default parser used to parse fields.
+ *
+ * @return the default field parser
+ */
+ public static DefaultFieldParser getParser() {
+ return PARSER;
}
+
+
+ /**
+ * Parses the given byte sequence and returns an instance of the
+ * Field
class. The type of the class returned depends on the
+ * field name; see {@link #parse(String)} for a table of field names and
+ * their corresponding classes.
+ *
+ * @param raw the bytes to parse.
+ * @param monitor a DecodeMonitor object used while parsing/decoding.
+ * @return a ParsedField
instance.
+ * @throws MimeException if the raw string cannot be split into field name and body.
+ */
+ public static ParsedField parse(
+ final ByteSequence raw,
+ final DecodeMonitor monitor) throws MimeException {
+ RawField rawField = new RawField(raw);
+ return PARSER.parse(rawField.getName(), rawField.getBody(), raw, monitor);
+ }
+
+ /**
+ * Parses the given string and returns an instance of the
+ * Field
class. The type of the class returned depends on
+ * the field name:
+ *
+ *
+ * Class returned | Field names |
+ * {@link ContentTypeFieldImpl} | Content-Type |
+ * {@link ContentTransferEncodingFieldImpl} | Content-Transfer-Encoding |
+ * {@link ContentDispositionFieldImpl} | Content-Disposition |
+ * {@link DateTimeFieldImpl} | Date, Resent-Date |
+ * {@link MailboxFieldImpl} | Sender, Resent-Sender |
+ * {@link MailboxListFieldImpl} | From, Resent-From |
+ * {@link AddressListFieldImpl} | To, Cc, Bcc, Reply-To, Resent-To, Resent-Cc, Resent-Bcc |
+ * {@link UnstructuredFieldImpl} | Subject and others |
+ *
+ *
+ * @param rawStr the string to parse.
+ * @return a ParsedField
instance.
+ * @throws MimeException if the raw string cannot be split into field name and body.
+ */
+ public static ParsedField parse(
+ final String rawStr,
+ final DecodeMonitor monitor) throws MimeException {
+ ByteSequence raw = ContentUtil.encode(rawStr);
+ return parse(raw, monitor);
+ }
+
+ public static ParsedField parse(final String rawStr) throws MimeException {
+ ByteSequence raw = ContentUtil.encode(rawStr);
+ return parse(raw, DecodeMonitor.SILENT);
+ }
+
+ public DefaultFieldParser() {
+ setFieldParser(FieldName.CONTENT_TRANSFER_ENCODING,
+ ContentTransferEncodingFieldImpl.PARSER);
+ setFieldParser(FieldName.CONTENT_TYPE, ContentTypeFieldImpl.PARSER);
+ setFieldParser(FieldName.CONTENT_DISPOSITION,
+ ContentDispositionFieldImpl.PARSER);
+
+ final FieldParser dateTimeParser = DateTimeFieldImpl.PARSER;
+ setFieldParser(FieldName.DATE, dateTimeParser);
+ setFieldParser(FieldName.RESENT_DATE, dateTimeParser);
+
+ final FieldParser mailboxListParser = MailboxListFieldImpl.PARSER;
+ setFieldParser(FieldName.FROM, mailboxListParser);
+ setFieldParser(FieldName.RESENT_FROM, mailboxListParser);
+
+ final FieldParser mailboxParser = MailboxFieldImpl.PARSER;
+ setFieldParser(FieldName.SENDER, mailboxParser);
+ setFieldParser(FieldName.RESENT_SENDER, mailboxParser);
+
+ final FieldParser addressListParser = AddressListFieldImpl.PARSER;
+ setFieldParser(FieldName.TO, addressListParser);
+ setFieldParser(FieldName.RESENT_TO, addressListParser);
+ setFieldParser(FieldName.CC, addressListParser);
+ setFieldParser(FieldName.RESENT_CC, addressListParser);
+ setFieldParser(FieldName.BCC, addressListParser);
+ setFieldParser(FieldName.RESENT_BCC, addressListParser);
+ setFieldParser(FieldName.REPLY_TO, addressListParser);
+ }
+
}
diff --git a/src/org/apache/james/mime4j/field/DelegatingFieldParser.java b/src/org/apache/james/mime4j/field/DelegatingFieldParser.java
index c06160292..2934b696a 100644
--- a/src/org/apache/james/mime4j/field/DelegatingFieldParser.java
+++ b/src/org/apache/james/mime4j/field/DelegatingFieldParser.java
@@ -1,47 +1,56 @@
-/*
- * Copyright 2006 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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 java.util.HashMap;
import java.util.Map;
-public class DelegatingFieldParser implements FieldParser {
-
- private Map parsers = new HashMap();
- private FieldParser defaultParser = new UnstructuredField.Parser();
-
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.field.UnstructuredFieldImpl;
+import org.apache.james.mime4j.util.ByteSequence;
+
+public class DelegatingFieldParser implements FieldParser {
+ private static final FieldParser DEFAULT_PARSER = UnstructuredFieldImpl.PARSER;
+
+ private Map> parsers = new HashMap>();
+
/**
* Sets the parser used for the field named name
.
* @param name the name of the field
* @param parser the parser for fields named name
*/
- public void setFieldParser(final String name, final FieldParser parser) {
+ public void setFieldParser(final String name, final FieldParser extends ParsedField> parser) {
parsers.put(name.toLowerCase(), parser);
}
- public FieldParser getParser(final String name) {
- final FieldParser field = (FieldParser) parsers.get(name.toLowerCase());
- if(field==null) {
- return defaultParser;
+ public FieldParser extends ParsedField> getParser(final String name) {
+ final FieldParser extends ParsedField> field = parsers.get(name.toLowerCase());
+ if (field == null) {
+ return DEFAULT_PARSER;
}
return field;
}
- public Field parse(final String name, final String body, final String raw) {
- final FieldParser parser = getParser(name);
- return parser.parse(name, body, raw);
+ public ParsedField parse(final String name, final String body, final ByteSequence raw, DecodeMonitor monitor) {
+ final FieldParser extends ParsedField> parser = getParser(name);
+ return parser.parse(name, body, raw, monitor);
}
}
diff --git a/src/org/apache/james/mime4j/field/Field.java b/src/org/apache/james/mime4j/field/Field.java
deleted file mode 100644
index 4dea5c5cf..000000000
--- a/src/org/apache/james/mime4j/field/Field.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/****************************************************************
- * 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 java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The base class of all field classes.
- *
- *
- * @version $Id: Field.java,v 1.6 2004/10/25 07:26:46 ntherning Exp $
- */
-public abstract class Field {
- public static final String SENDER = "Sender";
- public static final String FROM = "From";
- public static final String TO = "To";
- public static final String CC = "Cc";
- public static final String BCC = "Bcc";
- public static final String REPLY_TO = "Reply-To";
- public static final String RESENT_SENDER = "Resent-Sender";
- public static final String RESENT_FROM = "Resent-From";
- public static final String RESENT_TO = "Resent-To";
- public static final String RESENT_CC = "Resent-Cc";
- public static final String RESENT_BCC = "Resent-Bcc";
-
- public static final String DATE = "Date";
- public static final String RESENT_DATE = "Resent-Date";
-
- public static final String SUBJECT = "Subject";
- public static final String CONTENT_TYPE = "Content-Type";
- public static final String CONTENT_TRANSFER_ENCODING =
- "Content-Transfer-Encoding";
-
- private static final String FIELD_NAME_PATTERN =
- "^([\\x21-\\x39\\x3b-\\x7e]+)[ \t]*:";
- private static final Pattern fieldNamePattern =
- Pattern.compile(FIELD_NAME_PATTERN);
-
- private static final DefaultFieldParser parser = new DefaultFieldParser();
-
- private final String name;
- private final String body;
- private final String raw;
-
- protected Field(final String name, final String body, final String raw) {
- this.name = name;
- this.body = body;
- this.raw = raw;
- }
-
- /**
- * Parses the given string and returns an instance of the
- * Field
class. The type of the class returned depends on
- * the field name:
- *
- *
- * Field name | Class returned |
- * Content-Type | org.apache.james.mime4j.field.ContentTypeField |
- * other | org.apache.james.mime4j.field.UnstructuredField |
- *
- *
- *
- * @param s the string to parse.
- * @return a Field
instance.
- * @throws IllegalArgumentException on parse errors.
- */
- public static Field parse(final String raw) {
-
- /*
- * Unfold the field.
- */
- final String unfolded = raw.replaceAll("\r|\n", "");
-
- /*
- * Split into name and value.
- */
- final Matcher fieldMatcher = fieldNamePattern.matcher(unfolded);
- if (!fieldMatcher.find()) {
- throw new IllegalArgumentException("Invalid field in string");
- }
- final String name = fieldMatcher.group(1);
-
- String body = unfolded.substring(fieldMatcher.end());
- if (body.length() > 0 && body.charAt(0) == ' ') {
- body = body.substring(1);
- }
-
- return parser.parse(name, body, raw);
- }
-
- /**
- * Gets the default parser used to parse fields.
- * @return the default field parser
- */
- public static DefaultFieldParser getParser() {
- return parser;
- }
-
- /**
- * Gets the name of the field (Subject
,
- * From
, etc).
- *
- * @return the field name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Gets the original raw field string.
- *
- * @return the original raw field string.
- */
- public String getRaw() {
- return raw;
- }
-
- /**
- * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field
- * body string.
- *
- * @return the unfolded unparsed field body string.
- */
- public String getBody() {
- return body;
- }
-
- /**
- * Determines if this is a Content-Type
field.
- *
- * @return true
if this is a Content-Type
field,
- * false
otherwise.
- */
- public boolean isContentType() {
- return CONTENT_TYPE.equalsIgnoreCase(name);
- }
-
- /**
- * Determines if this is a Subject
field.
- *
- * @return true
if this is a Subject
field,
- * false
otherwise.
- */
- public boolean isSubject() {
- return SUBJECT.equalsIgnoreCase(name);
- }
-
- /**
- * Determines if this is a From
field.
- *
- * @return true
if this is a From
field,
- * false
otherwise.
- */
- public boolean isFrom() {
- return FROM.equalsIgnoreCase(name);
- }
-
- /**
- * Determines if this is a To
field.
- *
- * @return true
if this is a To
field,
- * false
otherwise.
- */
- public boolean isTo() {
- return TO.equalsIgnoreCase(name);
- }
-
- /**
- * @see #getRaw()
- */
- public String toString() {
- return raw;
- }
-}
diff --git a/src/org/apache/james/mime4j/field/FieldParser.java b/src/org/apache/james/mime4j/field/FieldParser.java
index 78aaf1334..fc19ddd58 100644
--- a/src/org/apache/james/mime4j/field/FieldParser.java
+++ b/src/org/apache/james/mime4j/field/FieldParser.java
@@ -1,21 +1,30 @@
-/*
- * Copyright 2006 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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;
-public interface FieldParser {
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.util.ByteSequence;
+
+public interface FieldParser {
+
+ T parse(final String name, final String body, final ByteSequence raw, DecodeMonitor monitor);
- Field parse(final String name, final String body, final String raw);
}
diff --git a/src/org/apache/james/mime4j/field/Fields.java b/src/org/apache/james/mime4j/field/Fields.java
new file mode 100644
index 000000000..cf2f3e5f6
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/Fields.java
@@ -0,0 +1,643 @@
+/****************************************************************
+ * 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 java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.regex.Pattern;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.field.AddressListField;
+import org.apache.james.mime4j.dom.field.ContentDispositionField;
+import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
+import org.apache.james.mime4j.dom.field.ContentTypeField;
+import org.apache.james.mime4j.dom.field.DateTimeField;
+import org.apache.james.mime4j.dom.field.Field;
+import org.apache.james.mime4j.dom.field.FieldName;
+import org.apache.james.mime4j.dom.field.MailboxField;
+import org.apache.james.mime4j.dom.field.MailboxListField;
+import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.dom.field.UnstructuredField;
+import org.apache.james.mime4j.field.AddressListFieldImpl;
+import org.apache.james.mime4j.field.ContentDispositionFieldImpl;
+import org.apache.james.mime4j.field.ContentTransferEncodingFieldImpl;
+import org.apache.james.mime4j.field.ContentTypeFieldImpl;
+import org.apache.james.mime4j.field.DateTimeFieldImpl;
+import org.apache.james.mime4j.field.MailboxFieldImpl;
+import org.apache.james.mime4j.field.MailboxListFieldImpl;
+import org.apache.james.mime4j.field.UnstructuredFieldImpl;
+import org.apache.james.mime4j.field.address.formatter.AddressFormatter;
+import org.apache.james.mime4j.stream.RawField;
+import org.apache.james.mime4j.util.MimeUtil;
+
+/**
+ * Factory for concrete {@link Field} instances.
+ */
+public class Fields {
+
+ private static final Pattern FIELD_NAME_PATTERN = Pattern
+ .compile("[\\x21-\\x39\\x3b-\\x7e]+");
+
+ private Fields() {
+ }
+
+ /**
+ * Creates a Content-Type field from the specified raw field value.
+ * The specified string gets folded into a multiple-line representation if
+ * necessary but is otherwise taken as is.
+ *
+ * @param contentType
+ * raw content type containing a MIME type and optional
+ * parameters.
+ * @return the newly created Content-Type field.
+ */
+ public static ContentTypeField contentType(String contentType) {
+ return parse(ContentTypeFieldImpl.PARSER, FieldName.CONTENT_TYPE,
+ contentType);
+ }
+
+ /**
+ * Creates a Content-Type field from the specified MIME type and
+ * parameters.
+ *
+ * @param mimeType
+ * a MIME type (such as "text/plain"
or
+ * "application/octet-stream"
).
+ * @param parameters
+ * map containing content-type parameters such as
+ * "boundary"
.
+ * @return the newly created Content-Type field.
+ */
+ public static ContentTypeField contentType(String mimeType,
+ Map parameters) {
+ if (!isValidMimeType(mimeType))
+ throw new IllegalArgumentException();
+
+ if (parameters == null || parameters.isEmpty()) {
+ return parse(ContentTypeFieldImpl.PARSER, FieldName.CONTENT_TYPE,
+ mimeType);
+ } else {
+ StringBuilder sb = new StringBuilder(mimeType);
+ for (Map.Entry entry : parameters.entrySet()) {
+ sb.append("; ");
+ sb.append(EncoderUtil.encodeHeaderParameter(entry.getKey(),
+ entry.getValue()));
+ }
+ String contentType = sb.toString();
+ return contentType(contentType);
+ }
+ }
+
+ /**
+ * Creates a Content-Transfer-Encoding field from the specified raw
+ * field value.
+ *
+ * @param contentTransferEncoding
+ * an encoding mechanism such as "7-bit"
+ * or "quoted-printable"
.
+ * @return the newly created Content-Transfer-Encoding field.
+ */
+ public static ContentTransferEncodingField contentTransferEncoding(
+ String contentTransferEncoding) {
+ return parse(ContentTransferEncodingFieldImpl.PARSER,
+ FieldName.CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
+ }
+
+ /**
+ * Creates a Content-Disposition field from the specified raw field
+ * value. The specified string gets folded into a multiple-line
+ * representation if necessary but is otherwise taken as is.
+ *
+ * @param contentDisposition
+ * raw content disposition containing a disposition type and
+ * optional parameters.
+ * @return the newly created Content-Disposition field.
+ */
+ public static ContentDispositionField contentDisposition(
+ String contentDisposition) {
+ return parse(ContentDispositionFieldImpl.PARSER,
+ FieldName.CONTENT_DISPOSITION, contentDisposition);
+ }
+
+ /**
+ * Creates a Content-Disposition field from the specified
+ * disposition type and parameters.
+ *
+ * @param dispositionType
+ * a disposition type (usually "inline"
+ * or "attachment"
).
+ * @param parameters
+ * map containing disposition parameters such as
+ * "filename"
.
+ * @return the newly created Content-Disposition field.
+ */
+ public static ContentDispositionField contentDisposition(
+ String dispositionType, Map parameters) {
+ if (!isValidDispositionType(dispositionType))
+ throw new IllegalArgumentException();
+
+ if (parameters == null || parameters.isEmpty()) {
+ return parse(ContentDispositionFieldImpl.PARSER,
+ FieldName.CONTENT_DISPOSITION, dispositionType);
+ } else {
+ StringBuilder sb = new StringBuilder(dispositionType);
+ for (Map.Entry entry : parameters.entrySet()) {
+ sb.append("; ");
+ sb.append(EncoderUtil.encodeHeaderParameter(entry.getKey(),
+ entry.getValue()));
+ }
+ String contentDisposition = sb.toString();
+ return contentDisposition(contentDisposition);
+ }
+ }
+
+ /**
+ * Creates a Content-Disposition field from the specified
+ * disposition type and filename.
+ *
+ * @param dispositionType
+ * a disposition type (usually "inline"
+ * or "attachment"
).
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should not be included.
+ * @return the newly created Content-Disposition field.
+ */
+ public static ContentDispositionField contentDisposition(
+ String dispositionType, String filename) {
+ return contentDisposition(dispositionType, filename, -1, null, null,
+ null);
+ }
+
+ /**
+ * Creates a Content-Disposition field from the specified values.
+ *
+ * @param dispositionType
+ * a disposition type (usually "inline"
+ * or "attachment"
).
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should not be included.
+ * @param size
+ * size parameter value or -1
if the parameter
+ * should not be included.
+ * @return the newly created Content-Disposition field.
+ */
+ public static ContentDispositionField contentDisposition(
+ String dispositionType, String filename, long size) {
+ return contentDisposition(dispositionType, filename, size, null, null,
+ null);
+ }
+
+ /**
+ * Creates a Content-Disposition field from the specified values.
+ *
+ * @param dispositionType
+ * a disposition type (usually "inline"
+ * or "attachment"
).
+ * @param filename
+ * filename parameter value or null
if the
+ * parameter should not be included.
+ * @param size
+ * size parameter value or -1
if the parameter
+ * should not be included.
+ * @param creationDate
+ * creation-date parameter value or null
if the
+ * parameter should not be included.
+ * @param modificationDate
+ * modification-date parameter value or null
if
+ * the parameter should not be included.
+ * @param readDate
+ * read-date parameter value or null
if the
+ * parameter should not be included.
+ * @return the newly created Content-Disposition field.
+ */
+ public static ContentDispositionField contentDisposition(
+ String dispositionType, String filename, long size,
+ Date creationDate, Date modificationDate, Date readDate) {
+ Map parameters = new HashMap();
+ if (filename != null) {
+ parameters.put(ContentDispositionFieldImpl.PARAM_FILENAME, filename);
+ }
+ if (size >= 0) {
+ parameters.put(ContentDispositionFieldImpl.PARAM_SIZE, Long
+ .toString(size));
+ }
+ if (creationDate != null) {
+ parameters.put(ContentDispositionFieldImpl.PARAM_CREATION_DATE,
+ MimeUtil.formatDate(creationDate, null));
+ }
+ if (modificationDate != null) {
+ parameters.put(ContentDispositionFieldImpl.PARAM_MODIFICATION_DATE,
+ MimeUtil.formatDate(modificationDate, null));
+ }
+ if (readDate != null) {
+ parameters.put(ContentDispositionFieldImpl.PARAM_READ_DATE, MimeUtil
+ .formatDate(readDate, null));
+ }
+ return contentDisposition(dispositionType, parameters);
+ }
+
+ /**
+ * Creates a Date field from the specified Date
+ * value. The default time zone of the host is used to format the date.
+ *
+ * @param date
+ * date value for the header field.
+ * @return the newly created Date field.
+ */
+ public static DateTimeField date(Date date) {
+ return date0(FieldName.DATE, date, null);
+ }
+
+ /**
+ * Creates a date field from the specified field name and Date
+ * value. The default time zone of the host is used to format the date.
+ *
+ * @param fieldName
+ * a field name such as Date
or
+ * Resent-Date
.
+ * @param date
+ * date value for the header field.
+ * @return the newly created date field.
+ */
+ public static DateTimeField date(String fieldName, Date date) {
+ checkValidFieldName(fieldName);
+ return date0(fieldName, date, null);
+ }
+
+ /**
+ * Creates a date field from the specified field name, Date
+ * and TimeZone
values.
+ *
+ * @param fieldName
+ * a field name such as Date
or
+ * Resent-Date
.
+ * @param date
+ * date value for the header field.
+ * @param zone
+ * the time zone to be used for formatting the date.
+ * @return the newly created date field.
+ */
+ public static DateTimeField date(String fieldName, Date date, TimeZone zone) {
+ checkValidFieldName(fieldName);
+ return date0(fieldName, date, zone);
+ }
+
+ /**
+ * Creates a Message-ID field for the specified host name.
+ *
+ * @param hostname
+ * host name to be included in the message ID or
+ * null
if no host name should be included.
+ * @return the newly created Message-ID field.
+ */
+ public static UnstructuredField messageId(String hostname) {
+ String fieldValue = MimeUtil.createUniqueMessageId(hostname);
+ return parse(UnstructuredFieldImpl.PARSER, FieldName.MESSAGE_ID, fieldValue);
+ }
+
+ /**
+ * Creates a Subject field from the specified string value. The
+ * specified string may contain non-ASCII characters.
+ *
+ * @param subject
+ * the subject string.
+ * @return the newly created Subject field.
+ */
+ public static UnstructuredField subject(String subject) {
+ int usedCharacters = FieldName.SUBJECT.length() + 2;
+ String fieldValue = EncoderUtil.encodeIfNecessary(subject,
+ EncoderUtil.Usage.TEXT_TOKEN, usedCharacters);
+
+ return parse(UnstructuredFieldImpl.PARSER, FieldName.SUBJECT, fieldValue);
+ }
+
+ /**
+ * Creates a Sender field for the specified mailbox address.
+ *
+ * @param mailbox
+ * address to be included in the field.
+ * @return the newly created Sender field.
+ */
+ public static MailboxField sender(Mailbox mailbox) {
+ return mailbox0(FieldName.SENDER, mailbox);
+ }
+
+ /**
+ * Creates a From field for the specified mailbox address.
+ *
+ * @param mailbox
+ * address to be included in the field.
+ * @return the newly created From field.
+ */
+ public static MailboxListField from(Mailbox mailbox) {
+ return mailboxList0(FieldName.FROM, Collections.singleton(mailbox));
+ }
+
+ /**
+ * Creates a From field for the specified mailbox addresses.
+ *
+ * @param mailboxes
+ * addresses to be included in the field.
+ * @return the newly created From field.
+ */
+ public static MailboxListField from(Mailbox... mailboxes) {
+ return mailboxList0(FieldName.FROM, Arrays.asList(mailboxes));
+ }
+
+ /**
+ * Creates a From field for the specified mailbox addresses.
+ *
+ * @param mailboxes
+ * addresses to be included in the field.
+ * @return the newly created From field.
+ */
+ public static MailboxListField from(Iterable mailboxes) {
+ return mailboxList0(FieldName.FROM, mailboxes);
+ }
+
+ /**
+ * Creates a To field for the specified mailbox or group address.
+ *
+ * @param address
+ * mailbox or group address to be included in the field.
+ * @return the newly created To field.
+ */
+ public static AddressListField to(Address address) {
+ return addressList0(FieldName.TO, Collections.singleton(address));
+ }
+
+ /**
+ * Creates a To field for the specified mailbox or group addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created To field.
+ */
+ public static AddressListField to(Address... addresses) {
+ return addressList0(FieldName.TO, Arrays.asList(addresses));
+ }
+
+ /**
+ * Creates a To field for the specified mailbox or group addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created To field.
+ */
+ public static AddressListField to(Iterable addresses) {
+ return addressList0(FieldName.TO, addresses);
+ }
+
+ /**
+ * Creates a Cc field for the specified mailbox or group address.
+ *
+ * @param address
+ * mailbox or group address to be included in the field.
+ * @return the newly created Cc field.
+ */
+ public static AddressListField cc(Address address) {
+ return addressList0(FieldName.CC, Collections.singleton(address));
+ }
+
+ /**
+ * Creates a Cc field for the specified mailbox or group addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created Cc field.
+ */
+ public static AddressListField cc(Address... addresses) {
+ return addressList0(FieldName.CC, Arrays.asList(addresses));
+ }
+
+ /**
+ * Creates a Cc field for the specified mailbox or group addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created Cc field.
+ */
+ public static AddressListField cc(Iterable addresses) {
+ return addressList0(FieldName.CC, addresses);
+ }
+
+ /**
+ * Creates a Bcc field for the specified mailbox or group address.
+ *
+ * @param address
+ * mailbox or group address to be included in the field.
+ * @return the newly created Bcc field.
+ */
+ public static AddressListField bcc(Address address) {
+ return addressList0(FieldName.BCC, Collections.singleton(address));
+ }
+
+ /**
+ * Creates a Bcc field for the specified mailbox or group addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created Bcc field.
+ */
+ public static AddressListField bcc(Address... addresses) {
+ return addressList0(FieldName.BCC, Arrays.asList(addresses));
+ }
+
+ /**
+ * Creates a Bcc field for the specified mailbox or group addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created Bcc field.
+ */
+ public static AddressListField bcc(Iterable addresses) {
+ return addressList0(FieldName.BCC, addresses);
+ }
+
+ /**
+ * Creates a Reply-To field for the specified mailbox or group
+ * address.
+ *
+ * @param address
+ * mailbox or group address to be included in the field.
+ * @return the newly created Reply-To field.
+ */
+ public static AddressListField replyTo(Address address) {
+ return addressList0(FieldName.REPLY_TO, Collections.singleton(address));
+ }
+
+ /**
+ * Creates a Reply-To field for the specified mailbox or group
+ * addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created Reply-To field.
+ */
+ public static AddressListField replyTo(Address... addresses) {
+ return addressList0(FieldName.REPLY_TO, Arrays.asList(addresses));
+ }
+
+ /**
+ * Creates a Reply-To field for the specified mailbox or group
+ * addresses.
+ *
+ * @param addresses
+ * mailbox or group addresses to be included in the field.
+ * @return the newly created Reply-To field.
+ */
+ public static AddressListField replyTo(Iterable addresses) {
+ return addressList0(FieldName.REPLY_TO, addresses);
+ }
+
+ /**
+ * Creates a mailbox field from the specified field name and mailbox
+ * address. Valid field names are Sender
and
+ * Resent-Sender
.
+ *
+ * @param fieldName
+ * the name of the mailbox field (Sender
or
+ * Resent-Sender
).
+ * @param mailbox
+ * mailbox address for the field value.
+ * @return the newly created mailbox field.
+ */
+ public static MailboxField mailbox(String fieldName, Mailbox mailbox) {
+ checkValidFieldName(fieldName);
+ return mailbox0(fieldName, mailbox);
+ }
+
+ /**
+ * Creates a mailbox-list field from the specified field name and mailbox
+ * addresses. Valid field names are From
and
+ * Resent-From
.
+ *
+ * @param fieldName
+ * the name of the mailbox field (From
or
+ * Resent-From
).
+ * @param mailboxes
+ * mailbox addresses for the field value.
+ * @return the newly created mailbox-list field.
+ */
+ public static MailboxListField mailboxList(String fieldName,
+ Iterable mailboxes) {
+ checkValidFieldName(fieldName);
+ return mailboxList0(fieldName, mailboxes);
+ }
+
+ /**
+ * Creates an address-list field from the specified field name and mailbox
+ * or group addresses. Valid field names are To
,
+ * Cc
, Bcc
, Reply-To
,
+ * Resent-To
, Resent-Cc
and
+ * Resent-Bcc
.
+ *
+ * @param fieldName
+ * the name of the mailbox field (To
,
+ * Cc
, Bcc
, Reply-To
,
+ * Resent-To
, Resent-Cc
or
+ * Resent-Bcc
).
+ * @param addresses
+ * mailbox or group addresses for the field value.
+ * @return the newly created address-list field.
+ */
+ public static AddressListField addressList(String fieldName,
+ Iterable addresses) {
+ checkValidFieldName(fieldName);
+ return addressList0(fieldName, addresses);
+ }
+
+ private static DateTimeField date0(String fieldName, Date date,
+ TimeZone zone) {
+ final String formattedDate = MimeUtil.formatDate(date, zone);
+ return parse(DateTimeFieldImpl.PARSER, fieldName, formattedDate);
+ }
+
+ private static MailboxField mailbox0(String fieldName, Mailbox mailbox) {
+ String fieldValue = encodeAddresses(Collections.singleton(mailbox));
+ return parse(MailboxFieldImpl.PARSER, fieldName, fieldValue);
+ }
+
+ private static MailboxListField mailboxList0(String fieldName,
+ Iterable mailboxes) {
+ String fieldValue = encodeAddresses(mailboxes);
+ return parse(MailboxListFieldImpl.PARSER, fieldName, fieldValue);
+ }
+
+ private static AddressListField addressList0(String fieldName,
+ Iterable addresses) {
+ String fieldValue = encodeAddresses(addresses);
+ return parse(AddressListFieldImpl.PARSER, fieldName, fieldValue);
+ }
+
+ private static void checkValidFieldName(String fieldName) {
+ if (!FIELD_NAME_PATTERN.matcher(fieldName).matches())
+ throw new IllegalArgumentException("Invalid field name");
+ }
+
+ private static boolean isValidMimeType(String mimeType) {
+ if (mimeType == null)
+ return false;
+
+ int idx = mimeType.indexOf('/');
+ if (idx == -1)
+ return false;
+
+ String type = mimeType.substring(0, idx);
+ String subType = mimeType.substring(idx + 1);
+ return EncoderUtil.isToken(type) && EncoderUtil.isToken(subType);
+ }
+
+ private static boolean isValidDispositionType(String dispositionType) {
+ if (dispositionType == null)
+ return false;
+
+ return EncoderUtil.isToken(dispositionType);
+ }
+
+ private static F parse(FieldParser parser,
+ String fieldName, String fieldBody) {
+ RawField rawField = new RawField(fieldName, fieldBody);
+ return parser.parse(rawField.getName(), rawField.getBody(), rawField.getRaw(),
+ DecodeMonitor.SILENT);
+ }
+
+ private static String encodeAddresses(Iterable extends Address> addresses) {
+ StringBuilder sb = new StringBuilder();
+
+ for (Address address : addresses) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ AddressFormatter.encode(sb, address);
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/MailboxField.java b/src/org/apache/james/mime4j/field/MailboxField.java
deleted file mode 100644
index 867a38a13..000000000
--- a/src/org/apache/james/mime4j/field/MailboxField.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************
- * 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.Mailbox;
-import org.apache.james.mime4j.field.address.MailboxList;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-
-public class MailboxField extends Field {
- private final Mailbox mailbox;
- private final ParseException parseException;
-
- protected MailboxField(final String name, final String body, final String raw, final Mailbox mailbox, final ParseException parseException) {
- super(name, body, raw);
- this.mailbox = mailbox;
- this.parseException = parseException;
- }
-
- public Mailbox getMailbox() {
- return mailbox;
- }
-
- public ParseException getParseException() {
- return parseException;
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- Mailbox mailbox = null;
- ParseException parseException = null;
- try {
- MailboxList mailboxList = AddressList.parse(body).flatten();
- if (mailboxList.size() > 0) {
- mailbox = mailboxList.get(0);
- }
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new MailboxField(name, body, raw, mailbox, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/MailboxFieldImpl.java b/src/org/apache/james/mime4j/field/MailboxFieldImpl.java
new file mode 100644
index 000000000..a4b648865
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/MailboxFieldImpl.java
@@ -0,0 +1,84 @@
+/****************************************************************
+ * 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.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.address.MailboxList;
+import org.apache.james.mime4j.field.address.parser.AddressBuilder;
+import org.apache.james.mime4j.field.address.parser.ParseException;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Mailbox field such as Sender
or Resent-Sender
.
+ */
+public class MailboxFieldImpl extends AbstractField implements org.apache.james.mime4j.dom.field.MailboxField {
+ private boolean parsed = false;
+
+ private Mailbox mailbox;
+ private ParseException parseException;
+
+ MailboxFieldImpl(final String name, final String body, final ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.MailboxField#getMailbox()
+ */
+ public Mailbox getMailbox() {
+ if (!parsed)
+ parse();
+
+ return mailbox;
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.MailboxField#getParseException()
+ */
+ @Override
+ public ParseException getParseException() {
+ if (!parsed)
+ parse();
+
+ return parseException;
+ }
+
+ private void parse() {
+ String body = getBody();
+
+ try {
+ MailboxList mailboxList = AddressBuilder.parseAddressList(body, monitor).flatten();
+ if (mailboxList.size() > 0) {
+ mailbox = mailboxList.get(0);
+ }
+ } catch (ParseException e) {
+ parseException = e;
+ }
+
+ parsed = true;
+ }
+
+ static final FieldParser PARSER = new FieldParser() {
+ public MailboxFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new MailboxFieldImpl(name, body, raw, monitor);
+ }
+ };
+}
diff --git a/src/org/apache/james/mime4j/field/MailboxListField.java b/src/org/apache/james/mime4j/field/MailboxListFieldImpl.java
similarity index 51%
rename from src/org/apache/james/mime4j/field/MailboxListField.java
rename to src/org/apache/james/mime4j/field/MailboxListFieldImpl.java
index e5b986dea..0e1cb8345 100644
--- a/src/org/apache/james/mime4j/field/MailboxListField.java
+++ b/src/org/apache/james/mime4j/field/MailboxListFieldImpl.java
@@ -19,47 +19,62 @@
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.MailboxList;
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.address.MailboxList;
+import org.apache.james.mime4j.field.address.parser.AddressBuilder;
import org.apache.james.mime4j.field.address.parser.ParseException;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Mailbox-list field such as From
or Resent-From
.
+ */
+public class MailboxListFieldImpl extends AbstractField implements org.apache.james.mime4j.dom.field.MailboxListField {
+ private boolean parsed = false;
-public class MailboxListField extends Field {
-
private MailboxList mailboxList;
private ParseException parseException;
- protected MailboxListField(final String name, final String body, final String raw, final MailboxList mailboxList, final ParseException parseException) {
- super(name, body, raw);
- this.mailboxList = mailboxList;
- this.parseException = parseException;
+ MailboxListFieldImpl(final String name, final String body, final ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
}
+ /**
+ * @see org.apache.james.mime4j.dom.field.MailboxListField#getMailboxList()
+ */
public MailboxList getMailboxList() {
+ if (!parsed)
+ parse();
+
return mailboxList;
}
+ /**
+ * @see org.apache.james.mime4j.dom.field.MailboxListField#getParseException()
+ */
+ @Override
public ParseException getParseException() {
+ if (!parsed)
+ parse();
+
return parseException;
}
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
- public Field parse(final String name, final String body, final String raw) {
- MailboxList mailboxList = null;
- ParseException parseException = null;
- try {
- mailboxList = AddressList.parse(body).flatten();
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new MailboxListField(name, body, raw, mailboxList, parseException);
+ private void parse() {
+ String body = getBody();
+
+ try {
+ mailboxList = AddressBuilder.parseAddressList(body, monitor).flatten();
+ } catch (ParseException e) {
+ parseException = e;
}
+
+ parsed = true;
}
+
+ static final FieldParser PARSER = new FieldParser() {
+ public MailboxListFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new MailboxListFieldImpl(name, body, raw, monitor);
+ }
+ };
}
diff --git a/src/org/apache/james/mime4j/field/UnstructuredFieldImpl.java b/src/org/apache/james/mime4j/field/UnstructuredFieldImpl.java
new file mode 100644
index 000000000..ea779e614
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/UnstructuredFieldImpl.java
@@ -0,0 +1,62 @@
+/****************************************************************
+ * 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.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.codec.DecoderUtil;
+import org.apache.james.mime4j.util.ByteSequence;
+
+/**
+ * Simple unstructured field such as Subject
.
+ */
+public class UnstructuredFieldImpl extends AbstractField implements org.apache.james.mime4j.dom.field.UnstructuredField {
+ private boolean parsed = false;
+
+ private String value;
+
+ UnstructuredFieldImpl(String name, String body, ByteSequence raw, DecodeMonitor monitor) {
+ super(name, body, raw, monitor);
+ }
+
+ /**
+ * @see org.apache.james.mime4j.dom.field.UnstructuredField#getValue()
+ */
+ public String getValue() {
+ if (!parsed)
+ parse();
+
+ return value;
+ }
+
+ private void parse() {
+ String body = getBody();
+
+ value = DecoderUtil.decodeEncodedWords(body, monitor);
+
+ parsed = true;
+ }
+
+ static final FieldParser PARSER = new FieldParser() {
+ public UnstructuredFieldImpl parse(final String name, final String body,
+ final ByteSequence raw, DecodeMonitor monitor) {
+ return new UnstructuredFieldImpl(name, body, raw, monitor);
+ }
+ };
+}
diff --git a/src/org/apache/james/mime4j/field/address/AddressList.java b/src/org/apache/james/mime4j/field/address/AddressList.java
deleted file mode 100644
index f623239d0..000000000
--- a/src/org/apache/james/mime4j/field/address/AddressList.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/****************************************************************
- * 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.address;
-
-import org.apache.james.mime4j.field.address.parser.AddressListParser;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-
-import java.io.StringReader;
-import java.util.ArrayList;
-
-/**
- * An immutable, random-access list of Address objects.
- *
- *
- */
-public class AddressList {
-
- private ArrayList addresses;
-
- /**
- * @param addresses An ArrayList that contains only Address objects.
- * @param dontCopy true iff it is not possible for the addresses ArrayList to be modified by someone else.
- */
- public AddressList(ArrayList addresses, boolean dontCopy) {
- if (addresses != null)
- this.addresses = (dontCopy ? addresses : (ArrayList) addresses.clone());
- else
- this.addresses = new ArrayList(0);
- }
-
- /**
- * The number of elements in this list.
- */
- public int size() {
- return addresses.size();
- }
-
- /**
- * Gets an address.
- */
- public Address get(int index) {
- if (0 > index || size() <= index)
- throw new IndexOutOfBoundsException();
- return (Address) addresses.get(index);
- }
-
- /**
- * Returns a flat list of all mailboxes represented
- * in this address list. Use this if you don't care
- * about grouping.
- */
- public MailboxList flatten() {
- // in the common case, all addresses are mailboxes
- boolean groupDetected = false;
- for (int i = 0; i < size(); i++) {
- if (!(get(i) instanceof Mailbox)) {
- groupDetected = true;
- break;
- }
- }
-
- if (!groupDetected)
- return new MailboxList(addresses, true);
-
- ArrayList results = new ArrayList();
- for (int i = 0; i < size(); i++) {
- Address addr = get(i);
- addr.addMailboxesTo(results);
- }
-
- // copy-on-construct this time, because subclasses
- // could have held onto a reference to the results
- return new MailboxList(results, false);
- }
-
- /**
- * Dumps a representation of this address list to
- * stdout, for debugging purposes.
- */
- public void print() {
- for (int i = 0; i < size(); i++) {
- Address addr = get(i);
- System.out.println(addr.toString());
- }
- }
-
-
-
- /**
- * Parse the address list string, such as the value
- * of a From, To, Cc, Bcc, Sender, or Reply-To
- * header.
- *
- * The string MUST be unfolded already.
- */
- public static AddressList parse(String rawAddressList) throws ParseException {
- AddressListParser parser = new AddressListParser(new StringReader(rawAddressList));
- return Builder.getInstance().buildAddressList(parser.parse());
- }
-
- /**
- * Test console.
- */
- public static void main(String[] args) throws Exception {
- java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
- while (true) {
- try {
- System.out.print("> ");
- String line = reader.readLine();
- if (line.length() == 0 || line.toLowerCase().equals("exit") || line.toLowerCase().equals("quit")) {
- System.out.println("Goodbye.");
- return;
- }
- AddressList list = parse(line);
- list.print();
- }
- catch(Exception e) {
- e.printStackTrace();
- Thread.sleep(300);
- }
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Builder.java b/src/org/apache/james/mime4j/field/address/Builder.java
deleted file mode 100644
index b17f4e3f7..000000000
--- a/src/org/apache/james/mime4j/field/address/Builder.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/****************************************************************
- * 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.address;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import org.apache.james.mime4j.decoder.DecoderUtil;
-import org.apache.james.mime4j.field.address.parser.*;
-import org.apache.james.mime4j.field.address.parser.ASTaddr_spec;
-import org.apache.james.mime4j.field.address.parser.ASTaddress;
-import org.apache.james.mime4j.field.address.parser.ASTaddress_list;
-import org.apache.james.mime4j.field.address.parser.ASTangle_addr;
-import org.apache.james.mime4j.field.address.parser.ASTdomain;
-import org.apache.james.mime4j.field.address.parser.ASTgroup_body;
-import org.apache.james.mime4j.field.address.parser.ASTlocal_part;
-import org.apache.james.mime4j.field.address.parser.ASTmailbox;
-import org.apache.james.mime4j.field.address.parser.ASTname_addr;
-import org.apache.james.mime4j.field.address.parser.ASTphrase;
-import org.apache.james.mime4j.field.address.parser.ASTroute;
-import org.apache.james.mime4j.field.address.parser.Node;
-import org.apache.james.mime4j.field.address.parser.SimpleNode;
-import org.apache.james.mime4j.field.address.parser.Token;
-
-/**
- * Transforms the JJTree-generated abstract syntax tree
- * into a graph of org.apache.james.mime4j.field.address objects.
- *
- *
- */
-class Builder {
-
- private static Builder singleton = new Builder();
-
- public static Builder getInstance() {
- return singleton;
- }
-
-
-
- public AddressList buildAddressList(ASTaddress_list node) {
- ArrayList list = new ArrayList();
- for (int i = 0; i < node.jjtGetNumChildren(); i++) {
- ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
- Address address = buildAddress(childNode);
- list.add(address);
- }
- return new AddressList(list, true);
- }
-
- private Address buildAddress(ASTaddress node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- Node n = it.nextNode();
- if (n instanceof ASTaddr_spec) {
- return buildAddrSpec((ASTaddr_spec)n);
- }
- else if (n instanceof ASTangle_addr) {
- return buildAngleAddr((ASTangle_addr)n);
- }
- else if (n instanceof ASTphrase) {
- String name = buildString((ASTphrase)n, false);
- Node n2 = it.nextNode();
- if (n2 instanceof ASTgroup_body) {
- return new Group(name, buildGroupBody((ASTgroup_body)n2));
- }
- else if (n2 instanceof ASTangle_addr) {
- name = DecoderUtil.decodeEncodedWords(name);
- return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2));
- }
- else {
- throw new IllegalStateException();
- }
- }
- else {
- throw new IllegalStateException();
- }
- }
-
-
-
- private MailboxList buildGroupBody(ASTgroup_body node) {
- ArrayList results = new ArrayList();
- ChildNodeIterator it = new ChildNodeIterator(node);
- while (it.hasNext()) {
- Node n = it.nextNode();
- if (n instanceof ASTmailbox)
- results.add(buildMailbox((ASTmailbox)n));
- else
- throw new IllegalStateException();
- }
- return new MailboxList(results, true);
- }
-
- private Mailbox buildMailbox(ASTmailbox node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- Node n = it.nextNode();
- if (n instanceof ASTaddr_spec) {
- return buildAddrSpec((ASTaddr_spec)n);
- }
- else if (n instanceof ASTangle_addr) {
- return buildAngleAddr((ASTangle_addr)n);
- }
- else if (n instanceof ASTname_addr) {
- return buildNameAddr((ASTname_addr)n);
- }
- else {
- throw new IllegalStateException();
- }
- }
-
- private NamedMailbox buildNameAddr(ASTname_addr node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- Node n = it.nextNode();
- String name;
- if (n instanceof ASTphrase) {
- name = buildString((ASTphrase)n, false);
- }
- else {
- throw new IllegalStateException();
- }
-
- n = it.nextNode();
- if (n instanceof ASTangle_addr) {
- name = DecoderUtil.decodeEncodedWords(name);
- return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n));
- }
- else {
- throw new IllegalStateException();
- }
- }
-
- private Mailbox buildAngleAddr(ASTangle_addr node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- DomainList route = null;
- Node n = it.nextNode();
- if (n instanceof ASTroute) {
- route = buildRoute((ASTroute)n);
- n = it.nextNode();
- }
- else if (n instanceof ASTaddr_spec)
- ; // do nothing
- else
- throw new IllegalStateException();
-
- if (n instanceof ASTaddr_spec)
- return buildAddrSpec(route, (ASTaddr_spec)n);
- else
- throw new IllegalStateException();
- }
-
- private DomainList buildRoute(ASTroute node) {
- ArrayList results = new ArrayList(node.jjtGetNumChildren());
- ChildNodeIterator it = new ChildNodeIterator(node);
- while (it.hasNext()) {
- Node n = it.nextNode();
- if (n instanceof ASTdomain)
- results.add(buildString((ASTdomain)n, true));
- else
- throw new IllegalStateException();
- }
- return new DomainList(results, true);
- }
-
- private Mailbox buildAddrSpec(ASTaddr_spec node) {
- return buildAddrSpec(null, node);
- }
- private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- String localPart = buildString((ASTlocal_part)it.nextNode(), true);
- String domain = buildString((ASTdomain)it.nextNode(), true);
- return new Mailbox(route, localPart, domain);
- }
-
-
- private String buildString(SimpleNode node, boolean stripSpaces) {
- Token head = node.firstToken;
- Token tail = node.lastToken;
- StringBuffer out = new StringBuffer();
-
- while (head != tail) {
- out.append(head.image);
- head = head.next;
- if (!stripSpaces)
- addSpecials(out, head.specialToken);
- }
- out.append(tail.image);
-
- return out.toString();
- }
-
- private void addSpecials(StringBuffer out, Token specialToken) {
- if (specialToken != null) {
- addSpecials(out, specialToken.specialToken);
- out.append(specialToken.image);
- }
- }
-
- private static class ChildNodeIterator implements Iterator {
-
- private SimpleNode simpleNode;
- private int index;
- private int len;
-
- public ChildNodeIterator(SimpleNode simpleNode) {
- this.simpleNode = simpleNode;
- this.len = simpleNode.jjtGetNumChildren();
- this.index = 0;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public boolean hasNext() {
- return index < len;
- }
-
- public Object next() {
- return nextNode();
- }
-
- public Node nextNode() {
- return simpleNode.jjtGetChild(index++);
- }
-
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/DomainList.java b/src/org/apache/james/mime4j/field/address/DomainList.java
deleted file mode 100644
index d90b22285..000000000
--- a/src/org/apache/james/mime4j/field/address/DomainList.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************
- * 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.address;
-
-import java.util.ArrayList;
-
-/**
- * An immutable, random-access list of Strings (that
- * are supposedly domain names or domain literals).
- *
- *
- */
-public class DomainList {
- private ArrayList domains;
-
- /**
- * @param domains An ArrayList that contains only String objects.
- * @param dontCopy true iff it is not possible for the domains ArrayList to be modified by someone else.
- */
- public DomainList(ArrayList domains, boolean dontCopy) {
- if (domains != null)
- this.domains = (dontCopy ? domains : (ArrayList) domains.clone());
- else
- this.domains = new ArrayList(0);
- }
-
- /**
- * The number of elements in this list.
- */
- public int size() {
- return domains.size();
- }
-
- /**
- * Gets the domain name or domain literal at the
- * specified index.
- * @throws IndexOutOfBoundsException If index is < 0 or >= size().
- */
- public String get(int index) {
- if (0 > index || size() <= index)
- throw new IndexOutOfBoundsException();
- return (String) domains.get(index);
- }
-
- /**
- * Returns the list of domains formatted as a route
- * string (not including the trailing ':').
- */
- public String toRouteString() {
- StringBuffer out = new StringBuffer();
- for (int i = 0; i < domains.size(); i++) {
- out.append("@");
- out.append(get(i));
- if (i + 1 < domains.size())
- out.append(",");
- }
- return out.toString();
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Group.java b/src/org/apache/james/mime4j/field/address/Group.java
deleted file mode 100644
index 63e294549..000000000
--- a/src/org/apache/james/mime4j/field/address/Group.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************
- * 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.address;
-
-import java.util.ArrayList;
-
-/**
- * A named group of zero or more mailboxes.
- *
- *
- */
-public class Group extends Address {
- private String name;
- private MailboxList mailboxList;
-
- /**
- * @param name The group name.
- * @param mailboxes The mailboxes in this group.
- */
- public Group(String name, MailboxList mailboxes) {
- this.name = name;
- this.mailboxList = mailboxes;
- }
-
- /**
- * Returns the group name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the mailboxes in this group.
- */
- public MailboxList getMailboxes() {
- return mailboxList;
- }
-
- public String toString() {
- StringBuffer buf = new StringBuffer();
- buf.append(name);
- buf.append(":");
- for (int i = 0; i < mailboxList.size(); i++) {
- buf.append(mailboxList.get(i).toString());
- if (i + 1 < mailboxList.size())
- buf.append(",");
- }
- buf.append(";");
- return buf.toString();
- }
-
- protected void doAddMailboxesTo(ArrayList results) {
- for (int i = 0; i < mailboxList.size(); i++)
- results.add(mailboxList.get(i));
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Mailbox.java b/src/org/apache/james/mime4j/field/address/Mailbox.java
deleted file mode 100644
index 1bc32b818..000000000
--- a/src/org/apache/james/mime4j/field/address/Mailbox.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/****************************************************************
- * 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.address;
-
-import java.util.ArrayList;
-
-/**
- * Represents a single e-mail address.
- *
- *
- */
-public class Mailbox extends Address {
- private DomainList route;
- private String localPart;
- private String domain;
-
- /**
- * Creates a mailbox without a route. Routes are obsolete.
- * @param localPart The part of the e-mail address to the left of the "@".
- * @param domain The part of the e-mail address to the right of the "@".
- */
- public Mailbox(String localPart, String domain) {
- this(null, localPart, domain);
- }
-
- /**
- * Creates a mailbox with a route. Routes are obsolete.
- * @param route The zero or more domains that make up the route. Can be null.
- * @param localPart The part of the e-mail address to the left of the "@".
- * @param domain The part of the e-mail address to the right of the "@".
- */
- public Mailbox(DomainList route, String localPart, String domain) {
- this.route = route;
- this.localPart = localPart;
- this.domain = domain;
- }
-
- /**
- * Returns the route list.
- */
- public DomainList getRoute() {
- return route;
- }
-
- /**
- * Returns the left part of the e-mail address
- * (before "@").
- */
- public String getLocalPart() {
- return localPart;
- }
-
- /**
- * Returns the right part of the e-mail address
- * (after "@").
- */
- public String getDomain() {
- return domain;
- }
-
- /**
- * Formats the address as a string, not including
- * the route.
- *
- * @see #getAddressString(boolean)
- */
- public String getAddressString() {
- return getAddressString(false);
- }
-
- /**
- * Note that this value may not be usable
- * for transport purposes, only display purposes.
- *
- * For example, if the unparsed address was
- *
- * <"Joe Cheng"@joecheng.com>
- *
- * this method would return
- *
- *
- *
- * which is not valid for transport; the local part
- * would need to be re-quoted.
- *
- * @param includeRoute true if the route should be included if it exists.
- */
- public String getAddressString(boolean includeRoute) {
- return "<" + (!includeRoute || route == null ? "" : route.toRouteString() + ":")
- + localPart
- + (domain == null ? "" : "@")
- + domain + ">";
- }
-
- protected final void doAddMailboxesTo(ArrayList results) {
- results.add(this);
- }
-
- public String toString() {
- return getAddressString();
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/NamedMailbox.java b/src/org/apache/james/mime4j/field/address/NamedMailbox.java
deleted file mode 100644
index 36b800c81..000000000
--- a/src/org/apache/james/mime4j/field/address/NamedMailbox.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************
- * 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.address;
-
-/**
- * A Mailbox that has a name/description.
- *
- *
- */
-public class NamedMailbox extends Mailbox {
- private String name;
-
- /**
- * @see Mailbox#Mailbox(String, String)
- */
- public NamedMailbox(String name, String localPart, String domain) {
- super(localPart, domain);
- this.name = name;
- }
-
- /**
- * @see Mailbox#Mailbox(DomainList, String, String)
- */
- public NamedMailbox(String name, DomainList route, String localPart, String domain) {
- super(route, localPart, domain);
- this.name = name;
- }
-
- /**
- * Creates a named mailbox based on an unnamed mailbox.
- */
- public NamedMailbox(String name, Mailbox baseMailbox) {
- super(baseMailbox.getRoute(), baseMailbox.getLocalPart(), baseMailbox.getDomain());
- this.name = name;
- }
-
- /**
- * Returns the name of the mailbox.
- */
- public String getName() {
- return this.name;
- }
-
- /**
- * Same features (or problems) as Mailbox.getAddressString(boolean),
- * only more so.
- *
- * @see Mailbox#getAddressString(boolean)
- */
- public String getAddressString(boolean includeRoute) {
- return (name == null ? "" : name + " ") + super.getAddressString(includeRoute);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/formatter/AddressFormatter.java b/src/org/apache/james/mime4j/field/address/formatter/AddressFormatter.java
new file mode 100644
index 000000000..5b0d91394
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/address/formatter/AddressFormatter.java
@@ -0,0 +1,209 @@
+/****************************************************************
+ * 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.address.formatter;
+
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.Group;
+import org.apache.james.mime4j.dom.address.Mailbox;
+
+public class AddressFormatter {
+
+ /**
+ * Formats the address as a human readable string, not including the route.
+ * The resulting string is intended for display purposes only and cannot be
+ * used for transport purposes.
+ *
+ * For example, if the unparsed address was
+ *
+ * <"Joe Cheng"@joecheng.com>
+ *
+ * this method would return
+ *
+ *
+ *
+ * which is not valid for transport; the local part would need to be
+ * re-quoted.
+ *
+ * @param includeRoute
+ * true
if the route should be included if it
+ * exists, false
otherwise.
+ * @return a string representation of this address intended to be displayed.
+ */
+ public static void format(final StringBuilder sb, final Address address, boolean includeRoute) {
+ if (address == null) {
+ return;
+ }
+ if (address instanceof Mailbox) {
+ format(sb, (Mailbox) address, includeRoute);
+ } else if (address instanceof Group) {
+ format(sb, (Group) address, includeRoute);
+ } else {
+ throw new IllegalArgumentException("Unsuppported Address class: " + address.getClass());
+ }
+ }
+
+ /**
+ * Returns a string representation of this address that can be used for
+ * transport purposes. The route is never included in this representation
+ * because routes are obsolete and RFC 5322 states that obsolete syntactic
+ * forms MUST NOT be generated.
+ *
+ * @return a string representation of this address intended for transport
+ * purposes.
+ */
+ public static void encode(final StringBuilder sb, final Address address) {
+ if (address == null) {
+ return;
+ }
+ if (address instanceof Mailbox) {
+ encode(sb, (Mailbox) address);
+ } else if (address instanceof Group) {
+ encode(sb, (Group) address);
+ } else {
+ throw new IllegalArgumentException("Unsuppported Address class: " + address.getClass());
+ }
+ }
+
+ public static void format(final StringBuilder sb, final Mailbox mailbox, boolean includeRoute) {
+ if (sb == null) {
+ throw new IllegalArgumentException("StringBuilder may not be null");
+ }
+ if (mailbox == null) {
+ throw new IllegalArgumentException("Mailbox may not be null");
+ }
+ includeRoute &= mailbox.getRoute() != null;
+ boolean includeAngleBrackets = mailbox.getName() != null || includeRoute;
+ if (mailbox.getName() != null) {
+ sb.append(mailbox.getName());
+ sb.append(' ');
+ }
+ if (includeAngleBrackets) {
+ sb.append('<');
+ }
+ if (includeRoute) {
+ sb.append(mailbox.getRoute().toRouteString());
+ sb.append(':');
+ }
+ sb.append(mailbox.getLocalPart());
+ if (mailbox.getDomain() != null) {
+ sb.append('@');
+ sb.append(mailbox.getDomain());
+ }
+ if (includeAngleBrackets) {
+ sb.append('>');
+ }
+ }
+
+ public static String format(final Mailbox mailbox, boolean includeRoute) {
+ StringBuilder sb = new StringBuilder();
+ format(sb, mailbox, includeRoute);
+ return sb.toString();
+ }
+
+ public static void encode(final StringBuilder sb, final Mailbox mailbox) {
+ if (sb == null) {
+ throw new IllegalArgumentException("StringBuilder may not be null");
+ }
+ if (mailbox == null) {
+ throw new IllegalArgumentException("Mailbox may not be null");
+ }
+ if (mailbox.getName() != null) {
+ sb.append(EncoderUtil.encodeAddressDisplayName(mailbox.getName()));
+ sb.append(" <");
+ }
+ sb.append(EncoderUtil.encodeAddressLocalPart(mailbox.getLocalPart()));
+ // domain = dot-atom / domain-literal
+ // domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
+ // dtext = %d33-90 / %d94-126
+ if (mailbox.getDomain() != null) {
+ sb.append('@');
+ sb.append(mailbox.getDomain());
+ }
+ if (mailbox.getName() != null) {
+ sb.append('>');
+ }
+ }
+
+ public static String encode(final Mailbox mailbox) {
+ StringBuilder sb = new StringBuilder();
+ encode(sb, mailbox);
+ return sb.toString();
+ }
+
+ public static void format(final StringBuilder sb, final Group group, boolean includeRoute) {
+ if (sb == null) {
+ throw new IllegalArgumentException("StringBuilder may not be null");
+ }
+ if (group == null) {
+ throw new IllegalArgumentException("Group may not be null");
+ }
+ sb.append(group.getName());
+ sb.append(':');
+
+ boolean first = true;
+ for (Mailbox mailbox : group.getMailboxes()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(' ');
+ format(sb, mailbox, includeRoute);
+ }
+ sb.append(";");
+ }
+
+ public static String format(final Group group, boolean includeRoute) {
+ StringBuilder sb = new StringBuilder();
+ format(sb, group, includeRoute);
+ return sb.toString();
+ }
+
+ public static void encode(final StringBuilder sb, final Group group) {
+ if (sb == null) {
+ throw new IllegalArgumentException("StringBuilder may not be null");
+ }
+ if (group == null) {
+ throw new IllegalArgumentException("Group may not be null");
+ }
+ sb.append(EncoderUtil.encodeAddressDisplayName(group.getName()));
+ sb.append(':');
+ boolean first = true;
+ for (Mailbox mailbox : group.getMailboxes()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+
+ sb.append(' ');
+ encode(sb, mailbox);
+ }
+ sb.append(';');
+ }
+
+ public static String encode(final Group group) {
+ StringBuilder sb = new StringBuilder();
+ encode(sb, group);
+ return sb.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java
index 4d56d000b..881420d40 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTaddr_spec.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTaddr_spec.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTaddr_spec extends SimpleNode {
+public
+class ASTaddr_spec extends SimpleNode {
public ASTaddr_spec(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTaddr_spec extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=750ab0a2f6a942d3f4a7a7e076d12a4d (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java
index 47bdeda8e..419cb956b 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTaddress.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTaddress.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTaddress extends SimpleNode {
+public
+class ASTaddress extends SimpleNode {
public ASTaddress(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTaddress extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=73be0a52ecfe4cf5d5a926be94fbb411 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java
index 737840e38..d0a7f2433 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTaddress_list.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTaddress_list.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTaddress_list extends SimpleNode {
+public
+class ASTaddress_list extends SimpleNode {
public ASTaddress_list(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTaddress_list extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=6615a805f4abebfcf7252d9aad462299 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java b/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java
index 8cb8f421f..1a61e9345 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTangle_addr.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTangle_addr.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTangle_addr extends SimpleNode {
+public
+class ASTangle_addr extends SimpleNode {
public ASTangle_addr(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTangle_addr extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=2201bedb23ef9d1b75dd88b2a5571384 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java b/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java
index b52664386..93ec2ab16 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTdomain.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTdomain.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTdomain extends SimpleNode {
+public
+class ASTdomain extends SimpleNode {
public ASTdomain(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTdomain extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=0105eb2d00d34d34b0665fd5ced14d52 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java b/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java
index f6017b9fc..505490e79 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTgroup_body.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTgroup_body.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTgroup_body extends SimpleNode {
+public
+class ASTgroup_body extends SimpleNode {
public ASTgroup_body(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTgroup_body extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=29b09d0a20de5b5f3d7e08c7e325d23f (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java b/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java
index 5c244fa3e..bf1298a0e 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTlocal_part.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTlocal_part.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTlocal_part extends SimpleNode {
+public
+class ASTlocal_part extends SimpleNode {
public ASTlocal_part(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTlocal_part extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=42e77dd54203428772aecd61a95fc01c (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java b/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java
index aeb469da1..13b403b5e 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTmailbox.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTmailbox.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTmailbox extends SimpleNode {
+public
+class ASTmailbox extends SimpleNode {
public ASTmailbox(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTmailbox extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=246fe7d146969407e2c7977748e2fc99 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java b/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java
index 846c73167..67f8eb7cc 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTname_addr.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTname_addr.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTname_addr extends SimpleNode {
+public
+class ASTname_addr extends SimpleNode {
public ASTname_addr(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTname_addr extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=37e69dc07dfc157b3fb2449483ff82b6 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java b/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java
index 7d711c529..40d7a6788 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTphrase.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTphrase.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTphrase extends SimpleNode {
+public
+class ASTphrase extends SimpleNode {
public ASTphrase(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTphrase extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=f1c7166e3c5b192d1f6db62b8239b0be (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTroute.java b/src/org/apache/james/mime4j/field/address/parser/ASTroute.java
index 54ea11523..caae1f891 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ASTroute.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ASTroute.java
@@ -1,8 +1,9 @@
-/* Generated By:JJTree: Do not edit this line. ASTroute.java */
-
+/* Generated By:JJTree: Do not edit this line. ASTroute.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class ASTroute extends SimpleNode {
+public
+class ASTroute extends SimpleNode {
public ASTroute(int id) {
super(id);
}
@@ -17,3 +18,4 @@ public class ASTroute extends SimpleNode {
return visitor.visit(this, data);
}
}
+/* JavaCC - OriginalChecksum=bcec06c89402cfcb3700aefe8d5f14f9 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressBuilder.java b/src/org/apache/james/mime4j/field/address/parser/AddressBuilder.java
new file mode 100644
index 000000000..5db350734
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/address/parser/AddressBuilder.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * 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.address.parser;
+
+import java.io.StringReader;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.dom.address.Group;
+import org.apache.james.mime4j.dom.address.Mailbox;
+
+public class AddressBuilder {
+
+ /**
+ * Parses the specified raw string into an address.
+ *
+ * @param rawAddressString
+ * string to parse.
+ * @param monitor the DecodeMonitor to be used while parsing/decoding
+ * @return an Address
object for the specified string.
+ * @throws ParseException if the raw string does not represent a single address.
+ */
+ public static Address parseAddress(String rawAddressString, DecodeMonitor monitor) throws ParseException {
+ AddressListParser parser = new AddressListParser(new StringReader(
+ rawAddressString));
+ return Builder.getInstance().buildAddress(parser.parseAddress(), monitor);
+ }
+
+ public static Address parseAddress(String rawAddressString) throws ParseException {
+ return parseAddress(rawAddressString, DecodeMonitor.STRICT);
+ }
+
+ /**
+ * Parse the address list string, such as the value of a From, To, Cc, Bcc,
+ * Sender, or Reply-To header.
+ *
+ * The string MUST be unfolded already.
+ * @param monitor the DecodeMonitor to be used while parsing/decoding
+ */
+ public static AddressList parseAddressList(String rawAddressList, DecodeMonitor monitor)
+ throws ParseException {
+ AddressListParser parser = new AddressListParser(new StringReader(
+ rawAddressList));
+ try {
+ return Builder.getInstance().buildAddressList(parser.parseAddressList(), monitor);
+ } catch (RuntimeException e) {
+ throw new ParseException(e.getMessage());
+ }
+ }
+
+ public static AddressList parseAddressList(String rawAddressList) throws ParseException {
+ return parseAddressList(rawAddressList, DecodeMonitor.STRICT);
+ }
+
+ /**
+ * Parses the specified raw string into a mailbox address.
+ *
+ * @param rawMailboxString
+ * string to parse.
+ * @param monitor the DecodeMonitor to be used while parsing/decoding.
+ * @return a Mailbox
object for the specified string.
+ * @throws ParseException
+ * if the raw string does not represent a single mailbox
+ * address.
+ */
+ public static Mailbox parseMailbox(String rawMailboxString, DecodeMonitor monitor) throws ParseException {
+ AddressListParser parser = new AddressListParser(new StringReader(
+ rawMailboxString));
+ return Builder.getInstance().buildMailbox(parser.parseMailbox(), monitor);
+ }
+
+ public static Mailbox parseMailbox(String rawMailboxString) throws ParseException {
+ return parseMailbox(rawMailboxString, DecodeMonitor.STRICT);
+ }
+
+ /**
+ * Parses the specified raw string into a group address.
+ *
+ * @param rawGroupString
+ * string to parse.
+ * @return a Group
object for the specified string.
+ * @throws ParseException
+ * if the raw string does not represent a single group address.
+ */
+ public static Group parseGroup(String rawGroupString, DecodeMonitor monitor) throws ParseException {
+ Address address = parseAddress(rawGroupString, monitor);
+ if (!(address instanceof Group))
+ throw new ParseException("Not a group address");
+
+ return (Group) address;
+ }
+
+ public static Group parseGroup(String rawGroupString) throws ParseException {
+ return parseGroup(rawGroupString, DecodeMonitor.STRICT);
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java
index 6cf08ac1d..c911691b4 100644
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java
+++ b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java
@@ -1,55 +1,71 @@
/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParser.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.address.parser;
public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants, AddressListParserConstants {/*@bgen(jjtree)*/
protected JJTAddressListParserState jjtree = new JJTAddressListParserState();public static void main(String args[]) throws ParseException {
- while (true) {
- try {
- AddressListParser parser = new AddressListParser(System.in);
- parser.parseLine();
- ((SimpleNode)parser.jjtree.rootNode()).dump("> ");
- } catch (Exception x) {
- x.printStackTrace();
- return;
- }
- }
+ while (true) {
+ try {
+ AddressListParser parser = new AddressListParser(System.in);
+ parser.parseLine();
+ ((SimpleNode) parser.jjtree.rootNode()).dump("> ");
+ } catch (Exception x) {
+ x.printStackTrace();
+ return;
+ }
+ }
}
- private static void log(String msg) {
- System.out.print(msg);
- }
-
- public ASTaddress_list parse() throws ParseException {
+ public ASTaddress_list parseAddressList() throws ParseException {
try {
- parseAll();
- return (ASTaddress_list)jjtree.rootNode();
+ parseAddressList0();
+ return (ASTaddress_list) jjtree.rootNode();
} catch (TokenMgrError tme) {
throw new ParseException(tme.getMessage());
}
}
+ public ASTaddress parseAddress() throws ParseException {
+ try {
+ parseAddress0();
+ return (ASTaddress) jjtree.rootNode();
+ } catch (TokenMgrError tme) {
+ throw new ParseException(tme.getMessage());
+ }
+ }
+
+ public ASTmailbox parseMailbox() throws ParseException {
+ try {
+ parseMailbox0();
+ return (ASTmailbox) jjtree.rootNode();
+ } catch (TokenMgrError tme) {
+ throw new ParseException(tme.getMessage());
+ }
+ }
void jjtreeOpenNodeScope(Node n) {
- ((SimpleNode)n).firstToken = getToken(1);
+ ((SimpleNode) n).firstToken = getToken(1);
}
void jjtreeCloseNodeScope(Node n) {
- ((SimpleNode)n).lastToken = getToken(0);
+ ((SimpleNode) n).lastToken = getToken(0);
}
final public void parseLine() throws ParseException {
@@ -65,11 +81,21 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
jj_consume_token(2);
}
- final public void parseAll() throws ParseException {
+ final public void parseAddressList0() throws ParseException {
address_list();
jj_consume_token(0);
}
+ final public void parseAddress0() throws ParseException {
+ address();
+ jj_consume_token(0);
+ }
+
+ final public void parseMailbox0() throws ParseException {
+ mailbox();
+ jj_consume_token(0);
+ }
+
final public void address_list() throws ParseException {
/*@bgen(jjtree) address_list */
ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST);
@@ -537,7 +563,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
jj_la1[17] = jj_gen;
;
}
- if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING)
+ if ( t.kind == AddressListParserConstants.QUOTEDSTRING || t.image.charAt(t.image.length() - 1) != '.')
{if (true) throw new ParseException("Words in local part must be separated by '.'");}
switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case DOTATOM:
@@ -610,21 +636,21 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
}
}
- final private boolean jj_2_1(int xla) {
+ private boolean jj_2_1(int xla) {
jj_la = xla; jj_lastpos = jj_scanpos = token;
try { return !jj_3_1(); }
catch(LookaheadSuccess ls) { return true; }
finally { jj_save(0, xla); }
}
- final private boolean jj_2_2(int xla) {
+ private boolean jj_2_2(int xla) {
jj_la = xla; jj_lastpos = jj_scanpos = token;
try { return !jj_3_2(); }
catch(LookaheadSuccess ls) { return true; }
finally { jj_save(1, xla); }
}
- final private boolean jj_3R_11() {
+ private boolean jj_3R_11() {
Token xsp;
xsp = jj_scanpos;
if (jj_scan_token(9)) jj_scanpos = xsp;
@@ -636,7 +662,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return false;
}
- final private boolean jj_3R_13() {
+ private boolean jj_3R_13() {
Token xsp;
xsp = jj_scanpos;
if (jj_scan_token(9)) jj_scanpos = xsp;
@@ -644,19 +670,19 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return false;
}
- final private boolean jj_3R_8() {
+ private boolean jj_3R_8() {
if (jj_3R_9()) return true;
if (jj_scan_token(8)) return true;
if (jj_3R_10()) return true;
return false;
}
- final private boolean jj_3_1() {
+ private boolean jj_3_1() {
if (jj_3R_8()) return true;
return false;
}
- final private boolean jj_3R_12() {
+ private boolean jj_3R_12() {
if (jj_scan_token(DOTATOM)) return true;
Token xsp;
while (true) {
@@ -666,7 +692,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return false;
}
- final private boolean jj_3R_10() {
+ private boolean jj_3R_10() {
Token xsp;
xsp = jj_scanpos;
if (jj_3R_12()) {
@@ -676,12 +702,12 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return false;
}
- final private boolean jj_3_2() {
+ private boolean jj_3_2() {
if (jj_3R_8()) return true;
return false;
}
- final private boolean jj_3R_9() {
+ private boolean jj_3R_9() {
Token xsp;
xsp = jj_scanpos;
if (jj_scan_token(14)) {
@@ -695,35 +721,39 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return false;
}
+ /** Generated Token Manager. */
public AddressListParserTokenManager token_source;
SimpleCharStream jj_input_stream;
- public Token token, jj_nt;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
private int jj_ntk;
private Token jj_scanpos, jj_lastpos;
private int jj_la;
- public boolean lookingAhead = false;
- private boolean jj_semLA;
private int jj_gen;
final private int[] jj_la1 = new int[22];
static private int[] jj_la1_0;
static private int[] jj_la1_1;
static {
- jj_la1_0();
- jj_la1_1();
+ jj_la1_init_0();
+ jj_la1_init_1();
}
- private static void jj_la1_0() {
+ private static void jj_la1_init_0() {
jj_la1_0 = new int[] {0x2,0x80004040,0x8,0x80004040,0x50,0x80004040,0x80004040,0x80004040,0x8,0x80004040,0x100,0x108,0x8,0x80004000,0x80004000,0x80004000,0x80004200,0x200,0x80004000,0x4200,0x200,0x44000,};
}
- private static void jj_la1_1() {
+ private static void jj_la1_init_1() {
jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,};
}
final private JJCalls[] jj_2_rtns = new JJCalls[2];
private boolean jj_rescan = false;
private int jj_gc = 0;
+ /** Constructor with InputStream. */
public AddressListParser(java.io.InputStream stream) {
this(stream, null);
}
+ /** Constructor with InputStream and supplied encoding */
public AddressListParser(java.io.InputStream stream, String encoding) {
try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
token_source = new AddressListParserTokenManager(jj_input_stream);
@@ -734,9 +764,11 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream stream) {
ReInit(stream, null);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream stream, String encoding) {
try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
token_source.ReInit(jj_input_stream);
@@ -748,6 +780,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
+ /** Constructor. */
public AddressListParser(java.io.Reader stream) {
jj_input_stream = new SimpleCharStream(stream, 1, 1);
token_source = new AddressListParserTokenManager(jj_input_stream);
@@ -758,6 +791,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader stream) {
jj_input_stream.ReInit(stream, 1, 1);
token_source.ReInit(jj_input_stream);
@@ -769,6 +803,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
+ /** Constructor with generated Token Manager. */
public AddressListParser(AddressListParserTokenManager tm) {
token_source = tm;
token = new Token();
@@ -778,6 +813,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
+ /** Reinitialise. */
public void ReInit(AddressListParserTokenManager tm) {
token_source = tm;
token = new Token();
@@ -788,7 +824,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
}
- final private Token jj_consume_token(int kind) throws ParseException {
+ private Token jj_consume_token(int kind) throws ParseException {
Token oldToken;
if ((oldToken = token).next != null) token = token.next;
else token = token.next = token_source.getNextToken();
@@ -814,7 +850,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
static private final class LookaheadSuccess extends java.lang.Error { }
final private LookaheadSuccess jj_ls = new LookaheadSuccess();
- final private boolean jj_scan_token(int kind) {
+ private boolean jj_scan_token(int kind) {
if (jj_scanpos == jj_lastpos) {
jj_la--;
if (jj_scanpos.next == null) {
@@ -835,6 +871,8 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return false;
}
+
+/** Get the next Token. */
final public Token getNextToken() {
if (token.next != null) token = token.next;
else token = token.next = token_source.getNextToken();
@@ -843,8 +881,9 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return token;
}
+/** Get the specific Token. */
final public Token getToken(int index) {
- Token t = lookingAhead ? jj_scanpos : token;
+ Token t = token;
for (int i = 0; i < index; i++) {
if (t.next != null) t = t.next;
else t = t.next = token_source.getNextToken();
@@ -852,14 +891,14 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
return t;
}
- final private int jj_ntk() {
+ private int jj_ntk() {
if ((jj_nt=token.next) == null)
return (jj_ntk = (token.next=token_source.getNextToken()).kind);
else
return (jj_ntk = jj_nt.kind);
}
- private java.util.Vector jj_expentries = new java.util.Vector();
+ private java.util.List jj_expentries = new java.util.ArrayList();
private int[] jj_expentry;
private int jj_kind = -1;
private int[] jj_lasttokens = new int[100];
@@ -874,31 +913,26 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
for (int i = 0; i < jj_endpos; i++) {
jj_expentry[i] = jj_lasttokens[i];
}
- boolean exists = false;
- for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) {
- int[] oldentry = (int[])(e.nextElement());
+ jj_entries_loop: for (java.util.Iterator> it = jj_expentries.iterator(); it.hasNext();) {
+ int[] oldentry = (int[])(it.next());
if (oldentry.length == jj_expentry.length) {
- exists = true;
for (int i = 0; i < jj_expentry.length; i++) {
if (oldentry[i] != jj_expentry[i]) {
- exists = false;
- break;
+ continue jj_entries_loop;
}
}
- if (exists) break;
+ jj_expentries.add(jj_expentry);
+ break jj_entries_loop;
}
}
- if (!exists) jj_expentries.addElement(jj_expentry);
if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
}
}
+ /** Generate ParseException. */
public ParseException generateParseException() {
- jj_expentries.removeAllElements();
+ jj_expentries.clear();
boolean[] la1tokens = new boolean[34];
- for (int i = 0; i < 34; i++) {
- la1tokens[i] = false;
- }
if (jj_kind >= 0) {
la1tokens[jj_kind] = true;
jj_kind = -1;
@@ -919,7 +953,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
if (la1tokens[i]) {
jj_expentry = new int[1];
jj_expentry[0] = i;
- jj_expentries.addElement(jj_expentry);
+ jj_expentries.add(jj_expentry);
}
}
jj_endpos = 0;
@@ -927,18 +961,20 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
jj_add_error_token(0, 0);
int[][] exptokseq = new int[jj_expentries.size()][];
for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = (int[])jj_expentries.elementAt(i);
+ exptokseq[i] = jj_expentries.get(i);
}
return new ParseException(token, exptokseq, tokenImage);
}
+ /** Enable tracing. */
final public void enable_tracing() {
}
+ /** Disable tracing. */
final public void disable_tracing() {
}
- final private void jj_rescan_token() {
+ private void jj_rescan_token() {
jj_rescan = true;
for (int i = 0; i < 2; i++) {
try {
@@ -958,7 +994,7 @@ public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeC
jj_rescan = false;
}
- final private void jj_save(int index, int xla) {
+ private void jj_save(int index, int xla) {
JJCalls p = jj_2_rtns[index];
while (p.gen > jj_gen) {
if (p.next == null) { p = p.next = new JJCalls(); break; }
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj
deleted file mode 100644
index 685988634..000000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj
+++ /dev/null
@@ -1,595 +0,0 @@
-/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParser.jj */
-/*@egen*//****************************************************************
- * 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. *
- ****************************************************************/
-
-
-/**
- * RFC2822 address list parser.
- *
- * Created 9/17/2004
- * by Joe Cheng
- */
-
-options {
- STATIC=false;
- LOOKAHEAD=1;
- //DEBUG_PARSER=true;
- //DEBUG_TOKEN_MANAGER=true;
-}
-
-PARSER_BEGIN(AddressListParser)
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.address.parser;
-
-public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants/*@egen*/ {/*@bgen(jjtree)*/
- protected JJTAddressListParserState jjtree = new JJTAddressListParserState();
-
-/*@egen*/
- public static void main(String args[]) throws ParseException {
- while (true) {
- try {
- AddressListParser parser = new AddressListParser(System.in);
- parser.parseLine();
- ((SimpleNode)parser.jjtree.rootNode()).dump("> ");
- } catch (Exception x) {
- x.printStackTrace();
- return;
- }
- }
- }
-
- private static void log(String msg) {
- System.out.print(msg);
- }
-
- public ASTaddress_list parse() throws ParseException {
- try {
- parseAll();
- return (ASTaddress_list)jjtree.rootNode();
- } catch (TokenMgrError tme) {
- throw new ParseException(tme.getMessage());
- }
- }
-
-
- void jjtreeOpenNodeScope(Node n) {
- ((SimpleNode)n).firstToken = getToken(1);
- }
-
- void jjtreeCloseNodeScope(Node n) {
- ((SimpleNode)n).lastToken = getToken(0);
- }
-}
-
-PARSER_END(AddressListParser)
-
-void parseLine() :
-{}
-{
- address_list() ["\r"] "\n"
-}
-
-void parseAll() :
-{}
-{
- address_list()
-}
-
-void address_list() :
-{/*@bgen(jjtree) address_list */
- ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) address_list */
- try {
-/*@egen*/
- [ address() ]
- (
- ","
- [ address() ]
- )*/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void address() :
-{/*@bgen(jjtree) address */
- ASTaddress jjtn000 = new ASTaddress(JJTADDRESS);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) address */
- try {
-/*@egen*/
- LOOKAHEAD(2147483647)
- addr_spec()
-| angle_addr()
-| ( phrase() (group_body() | angle_addr()) )/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void mailbox() :
-{/*@bgen(jjtree) mailbox */
- ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) mailbox */
- try {
-/*@egen*/
- LOOKAHEAD(2147483647)
- addr_spec()
-| angle_addr()
-| name_addr()/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void name_addr() :
-{/*@bgen(jjtree) name_addr */
- ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) name_addr */
- try {
-/*@egen*/
- phrase() angle_addr()/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void group_body() :
-{/*@bgen(jjtree) group_body */
- ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) group_body */
- try {
-/*@egen*/
- ":"
- [ mailbox() ]
- (
- ","
- [ mailbox() ]
- )*
- ";"/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void angle_addr() :
-{/*@bgen(jjtree) angle_addr */
- ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) angle_addr */
- try {
-/*@egen*/
- "<" [ route() ] addr_spec() ">"/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void route() :
-{/*@bgen(jjtree) route */
- ASTroute jjtn000 = new ASTroute(JJTROUTE);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) route */
- try {
-/*@egen*/
- "@" domain() ( (",")* "@" domain() )* ":"/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void phrase() :
-{/*@bgen(jjtree) phrase */
- ASTphrase jjtn000 = new ASTphrase(JJTPHRASE);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) phrase */
-try {
-/*@egen*/
-(
-|
-)+/*@bgen(jjtree)*/
-} finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
-}
-/*@egen*/
-}
-
-void addr_spec() :
-{/*@bgen(jjtree) addr_spec */
- ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) addr_spec */
- try {
-/*@egen*/
- ( local_part() "@" domain() )/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void local_part() :
-{/*@bgen(jjtree) local_part */
- ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/ Token t; }
-{/*@bgen(jjtree) local_part */
- try {
-/*@egen*/
- ( t= | t= )
- ( [t="."]
- {
- if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING)
- throw new ParseException("Words in local part must be separated by '.'");
- }
- ( t= | t= )
- )*/*@bgen(jjtree)*/
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void domain() :
-{/*@bgen(jjtree) domain */
- ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/ Token t; }
-{/*@bgen(jjtree) domain */
- try {
-/*@egen*/
- ( t=
- ( [t="."]
- {
- if (t.image.charAt(t.image.length() - 1) != '.')
- throw new ParseException("Atoms in domain names must be separated by '.'");
- }
- t=
- )*
- )
-| /*@bgen(jjtree)*/
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-SPECIAL_TOKEN :
-{
- < WS: ( [" ", "\t"] )+ >
-}
-
-TOKEN :
-{
- < #ALPHA: ["a" - "z", "A" - "Z"] >
-| < #DIGIT: ["0" - "9"] >
-| < #ATEXT: ( |
- | "!" | "#" | "$" | "%"
- | "&" | "'" | "*" | "+"
- | "-" | "/" | "=" | "?"
- | "^" | "_" | "`" | "{"
- | "|" | "}" | "~"
- )>
-| < DOTATOM: ( | "." )* >
-}
-
-TOKEN_MGR_DECLS :
-{
- // Keeps track of how many levels of comment nesting
- // we've encountered. This is only used when the 2nd
- // level is reached, for example ((this)), not (this).
- // This is because the outermost level must be treated
- // specially anyway, because the outermost ")" has a
- // different token type than inner ")" instances.
- static int commentNest;
-}
-
-MORE :
-{
- // domain literal
- "[" : INDOMAINLITERAL
-}
-
-
-MORE :
-{
- < > { image.deleteCharAt(image.length() - 2); }
-| < ~["[", "]", "\\"] >
-}
-
-
-TOKEN :
-{
- < DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT
-}
-
-MORE :
-{
- // starts a comment
- "(" : INCOMMENT
-}
-
-
-SKIP :
-{
- // ends a comment
- < COMMENT: ")" > : DEFAULT
- // if this is ever changed to not be a SKIP, need
- // to make sure matchedToken.token = token.toString()
- // is called.
-}
-
-
-MORE :
-{
- < > { image.deleteCharAt(image.length() - 2); }
-| "(" { commentNest = 1; } : NESTED_COMMENT
-| < >
-}
-
-
-MORE :
-{
- < > { image.deleteCharAt(image.length() - 2); }
-| "(" { ++commentNest; }
-| ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
-| < >
-}
-
-
-// QUOTED STRINGS
-
-MORE :
-{
- "\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING
-}
-
-
-MORE :
-{
- < > { image.deleteCharAt(image.length() - 2); }
-| < (~["\"", "\\"])+ >
-}
-
-
-TOKEN :
-{
- < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT
-}
-
-// GLOBALS
-
-<*>
-TOKEN :
-{
- < #QUOTEDPAIR: "\\" >
-| < #ANY: ~[] >
-}
-
-// ERROR!
-/*
-
-<*>
-TOKEN :
-{
- < UNEXPECTED_CHAR: >
-}
-
-*/
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java
index a21ad35db..a763ab604 100644
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java
+++ b/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java
@@ -1,41 +1,66 @@
/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserConstants.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.address.parser;
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
public interface AddressListParserConstants {
+ /** End of File. */
int EOF = 0;
+ /** RegularExpression Id. */
int WS = 10;
+ /** RegularExpression Id. */
int ALPHA = 11;
+ /** RegularExpression Id. */
int DIGIT = 12;
+ /** RegularExpression Id. */
int ATEXT = 13;
+ /** RegularExpression Id. */
int DOTATOM = 14;
+ /** RegularExpression Id. */
int DOMAINLITERAL = 18;
+ /** RegularExpression Id. */
int COMMENT = 20;
+ /** RegularExpression Id. */
int QUOTEDSTRING = 31;
+ /** RegularExpression Id. */
int QUOTEDPAIR = 32;
+ /** RegularExpression Id. */
int ANY = 33;
+ /** Lexical state. */
int DEFAULT = 0;
+ /** Lexical state. */
int INDOMAINLITERAL = 1;
+ /** Lexical state. */
int INCOMMENT = 2;
+ /** Lexical state. */
int NESTED_COMMENT = 3;
+ /** Lexical state. */
int INQUOTEDSTRING = 4;
+ /** Literal token values. */
String[] tokenImage = {
"",
"\"\\r\"",
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java
index df8974a3b..d6336d878 100644
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java
+++ b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java
@@ -1,21 +1,25 @@
/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserTokenManager.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.address.parser;
+/** Token Manager. */
public class AddressListParserTokenManager implements AddressListParserConstants
{
// Keeps track of how many levels of comment nesting
@@ -25,7 +29,10 @@ public class AddressListParserTokenManager implements AddressListParserConstants
// specially anyway, because the outermost ")" has a
// different token type than inner ")" instances.
static int commentNest;
+
+ /** Debug output. */
public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
private final int jjStopStringLiteralDfa_0(int pos, long active0)
{
@@ -39,21 +46,13 @@ private final int jjStartNfa_0(int pos, long active0)
{
return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
}
-private final int jjStopAtPos(int pos, int kind)
+private int jjStopAtPos(int pos, int kind)
{
jjmatchedKind = kind;
jjmatchedPos = pos;
return pos + 1;
}
-private final int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_0(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_0()
+private int jjMoveStringLiteralDfa0_0()
{
switch(curChar)
{
@@ -85,44 +84,13 @@ private final int jjMoveStringLiteralDfa0_0()
return jjMoveNfa_0(1, 0);
}
}
-private final void jjCheckNAdd(int state)
+private int jjMoveNfa_0(int startState, int curPos)
{
- if (jjrounds[state] != jjround)
- {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
- }
-}
-private final void jjAddStates(int start, int end)
-{
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
-}
-private final void jjCheckNAddTwoStates(int state1, int state2)
-{
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
-}
-private final void jjCheckNAddStates(int start, int end)
-{
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
-}
-private final void jjCheckNAddStates(int start)
-{
- jjCheckNAdd(jjnextStates[start]);
- jjCheckNAdd(jjnextStates[start + 1]);
-}
-private final int jjMoveNfa_0(int startState, int curPos)
-{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -130,7 +98,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -168,7 +136,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -188,7 +156,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -221,15 +189,7 @@ private final int jjStartNfa_2(int pos, long active0)
{
return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_2(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_2(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_2()
+private int jjMoveStringLiteralDfa0_2()
{
switch(curChar)
{
@@ -244,14 +204,13 @@ private final int jjMoveStringLiteralDfa0_2()
static final long[] jjbitVec0 = {
0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
};
-private final int jjMoveNfa_2(int startState, int curPos)
+private int jjMoveNfa_2(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -259,7 +218,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -278,7 +237,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -304,7 +263,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -345,15 +304,7 @@ private final int jjStartNfa_4(int pos, long active0)
{
return jjMoveNfa_4(jjStopStringLiteralDfa_4(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_4(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_4(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_4()
+private int jjMoveStringLiteralDfa0_4()
{
switch(curChar)
{
@@ -363,14 +314,13 @@ private final int jjMoveStringLiteralDfa0_4()
return jjMoveNfa_4(0, 0);
}
}
-private final int jjMoveNfa_4(int startState, int curPos)
+private int jjMoveNfa_4(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -378,7 +328,7 @@ private final int jjMoveNfa_4(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -401,7 +351,7 @@ private final int jjMoveNfa_4(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -434,7 +384,7 @@ private final int jjMoveNfa_4(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -479,15 +429,7 @@ private final int jjStartNfa_3(int pos, long active0)
{
return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_3(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_3(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_3()
+private int jjMoveStringLiteralDfa0_3()
{
switch(curChar)
{
@@ -499,14 +441,13 @@ private final int jjMoveStringLiteralDfa0_3()
return jjMoveNfa_3(0, 0);
}
}
-private final int jjMoveNfa_3(int startState, int curPos)
+private int jjMoveNfa_3(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -514,7 +455,7 @@ private final int jjMoveNfa_3(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -533,7 +474,7 @@ private final int jjMoveNfa_3(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -559,7 +500,7 @@ private final int jjMoveNfa_3(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -600,15 +541,7 @@ private final int jjStartNfa_1(int pos, long active0)
{
return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_1(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_1(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_1()
+private int jjMoveStringLiteralDfa0_1()
{
switch(curChar)
{
@@ -618,14 +551,13 @@ private final int jjMoveStringLiteralDfa0_1()
return jjMoveNfa_1(0, 0);
}
}
-private final int jjMoveNfa_1(int startState, int curPos)
+private int jjMoveNfa_1(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -633,7 +565,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -652,7 +584,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -681,7 +613,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -712,17 +644,23 @@ private final int jjMoveNfa_1(int startState, int curPos)
}
static final int[] jjnextStates = {
};
+
+/** Token literal values. */
public static final String[] jjstrLiteralImages = {
"", "\15", "\12", "\54", "\72", "\73", "\74", "\76", "\100", "\56", null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, };
+
+/** Lexer state names. */
public static final String[] lexStateNames = {
- "DEFAULT",
- "INDOMAINLITERAL",
- "INCOMMENT",
- "NESTED_COMMENT",
- "INQUOTEDSTRING",
+ "DEFAULT",
+ "INDOMAINLITERAL",
+ "INCOMMENT",
+ "NESTED_COMMENT",
+ "INQUOTEDSTRING",
};
+
+/** Lex State array. */
public static final int[] jjnewLexState = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, 2, 0, -1, 3, -1, -1,
-1, -1, -1, 4, -1, -1, 0, -1, -1,
@@ -742,19 +680,25 @@ static final long[] jjtoMore = {
protected SimpleCharStream input_stream;
private final int[] jjrounds = new int[3];
private final int[] jjstateSet = new int[6];
-StringBuffer image;
-int jjimageLen;
-int lengthOfMatch;
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
protected char curChar;
+/** Constructor. */
public AddressListParserTokenManager(SimpleCharStream stream){
if (SimpleCharStream.staticFlag)
throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
input_stream = stream;
}
+
+/** Constructor. */
public AddressListParserTokenManager(SimpleCharStream stream, int lexState){
this(stream);
SwitchTo(lexState);
}
+
+/** Reinitialise parser. */
public void ReInit(SimpleCharStream stream)
{
jjmatchedPos = jjnewStateCnt = 0;
@@ -762,18 +706,22 @@ public void ReInit(SimpleCharStream stream)
input_stream = stream;
ReInitRounds();
}
-private final void ReInitRounds()
+private void ReInitRounds()
{
int i;
jjround = 0x80000001;
for (i = 3; i-- > 0;)
jjrounds[i] = 0x80000000;
}
+
+/** Reinitialise parser. */
public void ReInit(SimpleCharStream stream, int lexState)
{
ReInit(stream);
SwitchTo(lexState);
}
+
+/** Switch to specified lex state. */
public void SwitchTo(int lexState)
{
if (lexState >= 5 || lexState < 0)
@@ -784,14 +732,25 @@ public void SwitchTo(int lexState)
protected Token jjFillToken()
{
- Token t = Token.newToken(jjmatchedKind);
- t.kind = jjmatchedKind;
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
String im = jjstrLiteralImages[jjmatchedKind];
- t.image = (im == null) ? input_stream.GetImage() : im;
- t.beginLine = input_stream.getBeginLine();
- t.beginColumn = input_stream.getBeginColumn();
- t.endLine = input_stream.getEndLine();
- t.endColumn = input_stream.getEndColumn();
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
return t;
}
@@ -802,28 +761,29 @@ int jjround;
int jjmatchedPos;
int jjmatchedKind;
+/** Get the next Token. */
public Token getNextToken()
{
- int kind;
Token specialToken = null;
Token matchedToken;
int curPos = 0;
EOFLoop :
for (;;)
- {
- try
- {
+ {
+ try
+ {
curChar = input_stream.BeginToken();
- }
+ }
catch(java.io.IOException e)
- {
+ {
jjmatchedKind = 0;
matchedToken = jjFillToken();
matchedToken.specialToken = specialToken;
return matchedToken;
}
- image = null;
+ image = jjimage;
+ image.setLength(0);
jjimageLen = 0;
for (;;)
@@ -927,62 +887,46 @@ void MoreLexicalActions()
switch(jjmatchedKind)
{
case 16 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 21 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 22 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
commentNest = 1;
break;
case 24 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 25 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
++commentNest;
break;
case 26 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
--commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
break;
case 28 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 1);
break;
case 29 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
- default :
+ default :
break;
}
}
@@ -991,19 +935,35 @@ void TokenLexicalActions(Token matchedToken)
switch(jjmatchedKind)
{
case 18 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
matchedToken.image = image.toString();
break;
case 31 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
matchedToken.image = image.substring(0, image.length() - 1);
break;
- default :
+ default :
break;
}
}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java
index 5987f19d8..38e6ca7b1 100644
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java
+++ b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java
@@ -1,5 +1,4 @@
-/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java */
-
+/* Generated By:JavaCC: Do not edit this line. AddressListParserTreeConstants.java Version 5.0 */
package org.apache.james.mime4j.field.address.parser;
public interface AddressListParserTreeConstants
@@ -33,3 +32,4 @@ public interface AddressListParserTreeConstants
"domain",
};
}
+/* JavaCC - OriginalChecksum=e7d2b24000a70a573955cf10036f0056 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java
index 8ec2fe7d2..674ffc5ed 100644
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java
+++ b/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java
@@ -1,5 +1,4 @@
-/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java */
-
+/* Generated By:JavaCC: Do not edit this line. AddressListParserVisitor.java Version 5.0 */
package org.apache.james.mime4j.field.address.parser;
public interface AddressListParserVisitor
@@ -17,3 +16,4 @@ public interface AddressListParserVisitor
public Object visit(ASTlocal_part node, Object data);
public Object visit(ASTdomain node, Object data);
}
+/* JavaCC - OriginalChecksum=f57edd9a1eb17afa5907a87b3c51e284 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/BaseNode.java b/src/org/apache/james/mime4j/field/address/parser/BaseNode.java
index 780974616..b7a901f4f 100644
--- a/src/org/apache/james/mime4j/field/address/parser/BaseNode.java
+++ b/src/org/apache/james/mime4j/field/address/parser/BaseNode.java
@@ -19,8 +19,6 @@
package org.apache.james.mime4j.field.address.parser;
-import org.apache.james.mime4j.field.address.parser.Node;
-import org.apache.james.mime4j.field.address.parser.Token;
public abstract class BaseNode implements Node {
diff --git a/src/org/apache/james/mime4j/field/address/parser/Builder.java b/src/org/apache/james/mime4j/field/address/parser/Builder.java
new file mode 100644
index 000000000..c4541a72b
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/address/parser/Builder.java
@@ -0,0 +1,229 @@
+/****************************************************************
+ * 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.address.parser;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.codec.DecoderUtil;
+import org.apache.james.mime4j.dom.address.Address;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.dom.address.DomainList;
+import org.apache.james.mime4j.dom.address.Group;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.address.MailboxList;
+
+/**
+ * Transforms the JJTree-generated abstract syntax tree into a graph of
+ * org.apache.james.mime4j.dom.address objects.
+ */
+class Builder {
+
+ private static Builder singleton = new Builder();
+
+ public static Builder getInstance() {
+ return singleton;
+ }
+
+ public AddressList buildAddressList(ASTaddress_list node, DecodeMonitor monitor) throws ParseException {
+ List list = new ArrayList();
+ for (int i = 0; i < node.jjtGetNumChildren(); i++) {
+ ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
+ Address address = buildAddress(childNode, monitor);
+ list.add(address);
+ }
+ return new AddressList(list, true);
+ }
+
+ public Address buildAddress(ASTaddress node, DecodeMonitor monitor) throws ParseException {
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ Node n = it.next();
+ if (n instanceof ASTaddr_spec) {
+ return buildAddrSpec((ASTaddr_spec) n);
+ } else if (n instanceof ASTangle_addr) {
+ return buildAngleAddr((ASTangle_addr) n);
+ } else if (n instanceof ASTphrase) {
+ String name = buildString((ASTphrase) n, false);
+ Node n2 = it.next();
+ if (n2 instanceof ASTgroup_body) {
+ return new Group(name, buildGroupBody((ASTgroup_body) n2, monitor));
+ } else if (n2 instanceof ASTangle_addr) {
+ try {
+ name = DecoderUtil.decodeEncodedWords(name, monitor);
+ } catch (IllegalArgumentException e) {
+ throw new ParseException(e.getMessage());
+ }
+ Mailbox mb = buildAngleAddr((ASTangle_addr) n2);
+ return new Mailbox(name, mb.getRoute(), mb.getLocalPart(),
+ mb.getDomain());
+ } else {
+ throw new ParseException();
+ }
+ } else {
+ throw new ParseException();
+ }
+ }
+
+ private MailboxList buildGroupBody(ASTgroup_body node, DecodeMonitor monitor) throws ParseException {
+ List results = new ArrayList();
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ while (it.hasNext()) {
+ Node n = it.next();
+ if (n instanceof ASTmailbox)
+ results.add(buildMailbox((ASTmailbox) n, monitor));
+ else
+ throw new ParseException();
+ }
+ return new MailboxList(results, true);
+ }
+
+ public Mailbox buildMailbox(ASTmailbox node, DecodeMonitor monitor) throws ParseException {
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ Node n = it.next();
+ if (n instanceof ASTaddr_spec) {
+ return buildAddrSpec((ASTaddr_spec) n);
+ } else if (n instanceof ASTangle_addr) {
+ return buildAngleAddr((ASTangle_addr) n);
+ } else if (n instanceof ASTname_addr) {
+ return buildNameAddr((ASTname_addr) n, monitor);
+ } else {
+ throw new ParseException();
+ }
+ }
+
+ private Mailbox buildNameAddr(ASTname_addr node, DecodeMonitor monitor) throws ParseException {
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ Node n = it.next();
+ String name;
+ if (n instanceof ASTphrase) {
+ name = buildString((ASTphrase) n, false);
+ } else {
+ throw new ParseException();
+ }
+
+ n = it.next();
+ if (n instanceof ASTangle_addr) {
+ try {
+ name = DecoderUtil.decodeEncodedWords(name, monitor);
+ } catch (IllegalArgumentException e) {
+ throw new ParseException(e.getMessage());
+ }
+ Mailbox mb = buildAngleAddr((ASTangle_addr) n);
+ return new Mailbox(name, mb.getRoute(), mb.getLocalPart(),
+ mb.getDomain());
+ } else {
+ throw new ParseException();
+ }
+ }
+
+ private Mailbox buildAngleAddr(ASTangle_addr node) throws ParseException {
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ DomainList route = null;
+ Node n = it.next();
+ if (n instanceof ASTroute) {
+ route = buildRoute((ASTroute) n);
+ n = it.next();
+ } else if (n instanceof ASTaddr_spec) {
+ // do nothing
+ }
+ else
+ throw new ParseException();
+
+ if (n instanceof ASTaddr_spec)
+ return buildAddrSpec(route, (ASTaddr_spec) n);
+ else
+ throw new ParseException();
+ }
+
+ private DomainList buildRoute(ASTroute node) throws ParseException {
+ List results = new ArrayList(node.jjtGetNumChildren());
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ while (it.hasNext()) {
+ Node n = it.next();
+ if (n instanceof ASTdomain)
+ results.add(buildString((ASTdomain) n, true));
+ else
+ throw new ParseException();
+ }
+ return new DomainList(results, true);
+ }
+
+ private Mailbox buildAddrSpec(ASTaddr_spec node) {
+ return buildAddrSpec(null, node);
+ }
+
+ private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
+ ChildNodeIterator it = new ChildNodeIterator(node);
+ String localPart = buildString((ASTlocal_part) it.next(), true);
+ String domain = buildString((ASTdomain) it.next(), true);
+ return new Mailbox(route, localPart, domain);
+ }
+
+ private String buildString(SimpleNode node, boolean stripSpaces) {
+ Token head = node.firstToken;
+ Token tail = node.lastToken;
+ StringBuilder out = new StringBuilder();
+
+ while (head != tail) {
+ out.append(head.image);
+ head = head.next;
+ if (!stripSpaces)
+ addSpecials(out, head.specialToken);
+ }
+ out.append(tail.image);
+
+ return out.toString();
+ }
+
+ private void addSpecials(StringBuilder out, Token specialToken) {
+ if (specialToken != null) {
+ addSpecials(out, specialToken.specialToken);
+ out.append(specialToken.image);
+ }
+ }
+
+ private static class ChildNodeIterator implements Iterator {
+
+ private SimpleNode simpleNode;
+ private int index;
+ private int len;
+
+ public ChildNodeIterator(SimpleNode simpleNode) {
+ this.simpleNode = simpleNode;
+ this.len = simpleNode.jjtGetNumChildren();
+ this.index = 0;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasNext() {
+ return index < len;
+ }
+
+ public Node next() {
+ return simpleNode.jjtGetChild(index++);
+ }
+
+ }
+}
diff --git a/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java b/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java
index cca539483..0a88d8241 100644
--- a/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java
+++ b/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java
@@ -1,18 +1,17 @@
-/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java */
-
+/* Generated By:JavaCC: Do not edit this line. JJTAddressListParserState.java Version 5.0 */
package org.apache.james.mime4j.field.address.parser;
-class JJTAddressListParserState {
- private java.util.Stack nodes;
- private java.util.Stack marks;
+public class JJTAddressListParserState {
+ private java.util.List nodes;
+ private java.util.List marks;
- private int sp; // number of nodes on stack
- private int mk; // current mark
+ private int sp; // number of nodes on stack
+ private int mk; // current mark
private boolean node_created;
- JJTAddressListParserState() {
- nodes = new java.util.Stack();
- marks = new java.util.Stack();
+ public JJTAddressListParserState() {
+ nodes = new java.util.ArrayList();
+ marks = new java.util.ArrayList();
sp = 0;
mk = 0;
}
@@ -20,62 +19,62 @@ class JJTAddressListParserState {
/* Determines whether the current node was actually closed and
pushed. This should only be called in the final user action of a
node scope. */
- boolean nodeCreated() {
+ public boolean nodeCreated() {
return node_created;
}
/* Call this to reinitialize the node stack. It is called
automatically by the parser's ReInit() method. */
- void reset() {
- nodes.removeAllElements();
- marks.removeAllElements();
+ public void reset() {
+ nodes.clear();
+ marks.clear();
sp = 0;
mk = 0;
}
/* Returns the root node of the AST. It only makes sense to call
this after a successful parse. */
- Node rootNode() {
- return (Node)nodes.elementAt(0);
+ public Node rootNode() {
+ return nodes.get(0);
}
/* Pushes a node on to the stack. */
- void pushNode(Node n) {
- nodes.push(n);
+ public void pushNode(Node n) {
+ nodes.add(n);
++sp;
}
/* Returns the node on the top of the stack, and remove it from the
stack. */
- Node popNode() {
+ public Node popNode() {
if (--sp < mk) {
- mk = ((Integer)marks.pop()).intValue();
+ mk = marks.remove(marks.size()-1);
}
- return (Node)nodes.pop();
+ return nodes.remove(nodes.size()-1);
}
/* Returns the node currently on the top of the stack. */
- Node peekNode() {
- return (Node)nodes.peek();
+ public Node peekNode() {
+ return nodes.get(nodes.size()-1);
}
/* Returns the number of children on the stack in the current node
scope. */
- int nodeArity() {
+ public int nodeArity() {
return sp - mk;
}
- void clearNodeScope(Node n) {
+ public void clearNodeScope(Node n) {
while (sp > mk) {
popNode();
}
- mk = ((Integer)marks.pop()).intValue();
+ mk = marks.remove(marks.size()-1);
}
- void openNodeScope(Node n) {
- marks.push(new Integer(mk));
+ public void openNodeScope(Node n) {
+ marks.add(mk);
mk = sp;
n.jjtOpen();
}
@@ -85,8 +84,8 @@ class JJTAddressListParserState {
children. That number of nodes are popped from the stack and
made the children of the definite node. Then the definite node
is pushed on to the stack. */
- void closeNodeScope(Node n, int num) {
- mk = ((Integer)marks.pop()).intValue();
+ public void closeNodeScope(Node n, int num) {
+ mk = marks.remove(marks.size()-1);
while (num-- > 0) {
Node c = popNode();
c.jjtSetParent(n);
@@ -100,24 +99,25 @@ class JJTAddressListParserState {
/* A conditional node is constructed if its condition is true. All
the nodes that have been pushed since the node was opened are
- made children of the the conditional node, which is then pushed
+ made children of the conditional node, which is then pushed
on to the stack. If the condition is false the node is not
constructed and they are left on the stack. */
- void closeNodeScope(Node n, boolean condition) {
+ public void closeNodeScope(Node n, boolean condition) {
if (condition) {
int a = nodeArity();
- mk = ((Integer)marks.pop()).intValue();
+ mk = marks.remove(marks.size()-1);
while (a-- > 0) {
- Node c = popNode();
- c.jjtSetParent(n);
- n.jjtAddChild(c, a);
+ Node c = popNode();
+ c.jjtSetParent(n);
+ n.jjtAddChild(c, a);
}
n.jjtClose();
pushNode(n);
node_created = true;
} else {
- mk = ((Integer)marks.pop()).intValue();
+ mk = marks.remove(marks.size()-1);
node_created = false;
}
}
}
+/* JavaCC - OriginalChecksum=e61a7a50ac6b2ea6fa91b5482005b3ce (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/Node.java b/src/org/apache/james/mime4j/field/address/parser/Node.java
index 158892016..8bf146b4e 100644
--- a/src/org/apache/james/mime4j/field/address/parser/Node.java
+++ b/src/org/apache/james/mime4j/field/address/parser/Node.java
@@ -1,12 +1,13 @@
-/* Generated By:JJTree: Do not edit this line. Node.java */
-
+/* Generated By:JJTree: Do not edit this line. Node.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
/* All AST nodes must implement this interface. It provides basic
machinery for constructing the parent and child relationships
between nodes. */
-public interface Node {
+public
+interface Node {
/** This method is called after the node has been made the current
node. It indicates that child nodes can now be added to it. */
@@ -35,3 +36,4 @@ public interface Node {
/** Accept the visitor. **/
public Object jjtAccept(AddressListParserVisitor visitor, Object data);
}
+/* JavaCC - OriginalChecksum=b3b1bedb94f5dcae7af8d6e02371fe1e (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/ParseException.java b/src/org/apache/james/mime4j/field/address/parser/ParseException.java
index 939c6cfed..e48ce5947 100644
--- a/src/org/apache/james/mime4j/field/address/parser/ParseException.java
+++ b/src/org/apache/james/mime4j/field/address/parser/ParseException.java
@@ -1,19 +1,22 @@
/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.address.parser;
/**
@@ -22,10 +25,15 @@ package org.apache.james.mime4j.field.address.parser;
* calling the method generateParseException in the generated
* parser.
*
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
*/
-public class ParseException extends Exception {
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
/**
* This constructor is used by the method "generateParseException"
@@ -62,7 +70,12 @@ public class ParseException extends Exception {
*/
public ParseException() {
- super();
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
specialConstructor = false;
}
diff --git a/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java
index 957bbeabc..64513a966 100644
--- a/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java
+++ b/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java
@@ -1,19 +1,23 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.address.parser;
/**
@@ -23,10 +27,12 @@ package org.apache.james.mime4j.field.address.parser;
public class SimpleCharStream
{
+/** Whether parser is static. */
public static final boolean staticFlag = false;
int bufsize;
int available;
int tokenBegin;
+/** Position in buffer. */
public int bufpos = -1;
protected int bufline[];
protected int bufcolumn[];
@@ -50,210 +56,218 @@ public class SimpleCharStream
protected void ExpandBuff(boolean wrapAround)
{
- char[] newbuffer = new char[bufsize + 2048];
- int newbufline[] = new int[bufsize + 2048];
- int newbufcolumn[] = new int[bufsize + 2048];
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
- try
- {
- if (wrapAround)
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- System.arraycopy(buffer, 0, newbuffer,
- bufsize - tokenBegin, bufpos);
- buffer = newbuffer;
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
- bufline = newbufline;
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
- bufcolumn = newbufcolumn;
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
- maxNextCharInd = (bufpos += (bufsize - tokenBegin));
- }
- else
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- buffer = newbuffer;
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- bufline = newbufline;
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- bufcolumn = newbufcolumn;
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
- maxNextCharInd = (bufpos -= tokenBegin);
- }
- }
- catch (Throwable t)
- {
- throw new Error(t.getMessage());
- }
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
- bufsize += 2048;
- available = bufsize;
- tokenBegin = 0;
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
}
protected void FillBuff() throws java.io.IOException
{
- if (maxNextCharInd == available)
- {
- if (available == bufsize)
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
{
- if (tokenBegin > 2048)
- {
- bufpos = maxNextCharInd = 0;
- available = tokenBegin;
- }
- else if (tokenBegin < 0)
- bufpos = maxNextCharInd = 0;
- else
- ExpandBuff(false);
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
}
- else if (available > tokenBegin)
- available = bufsize;
- else if ((tokenBegin - available) < 2048)
- ExpandBuff(true);
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
else
- available = tokenBegin;
- }
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
- int i;
- try {
- if ((i = inputStream.read(buffer, maxNextCharInd,
- available - maxNextCharInd)) == -1)
- {
- inputStream.close();
- throw new java.io.IOException();
- }
- else
- maxNextCharInd += i;
- return;
- }
- catch(java.io.IOException e) {
- --bufpos;
- backup(0);
- if (tokenBegin == -1)
- tokenBegin = bufpos;
- throw e;
- }
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
}
+/** Start. */
public char BeginToken() throws java.io.IOException
{
- tokenBegin = -1;
- char c = readChar();
- tokenBegin = bufpos;
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
- return c;
+ return c;
}
protected void UpdateLineColumn(char c)
{
- column++;
+ column++;
- if (prevCharIsLF)
- {
- prevCharIsLF = false;
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
line += (column = 1);
- }
- else if (prevCharIsCR)
- {
- prevCharIsCR = false;
- if (c == '\n')
- {
- prevCharIsLF = true;
- }
- else
- line += (column = 1);
- }
+ }
- switch (c)
- {
- case '\r' :
- prevCharIsCR = true;
- break;
- case '\n' :
- prevCharIsLF = true;
- break;
- case '\t' :
- column--;
- column += (tabSize - (column % tabSize));
- break;
- default :
- break;
- }
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
- bufline[bufpos] = line;
- bufcolumn[bufpos] = column;
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
}
+/** Read a character. */
public char readChar() throws java.io.IOException
{
- if (inBuf > 0)
- {
- --inBuf;
+ if (inBuf > 0)
+ {
+ --inBuf;
- if (++bufpos == bufsize)
- bufpos = 0;
+ if (++bufpos == bufsize)
+ bufpos = 0;
- return buffer[bufpos];
- }
+ return buffer[bufpos];
+ }
- if (++bufpos >= maxNextCharInd)
- FillBuff();
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
- char c = buffer[bufpos];
+ char c = buffer[bufpos];
- UpdateLineColumn(c);
- return (c);
+ UpdateLineColumn(c);
+ return c;
}
+ @Deprecated
/**
- * @deprecated
+ * @deprecated
* @see #getEndColumn
*/
public int getColumn() {
- return bufcolumn[bufpos];
+ return bufcolumn[bufpos];
}
+ @Deprecated
/**
- * @deprecated
+ * @deprecated
* @see #getEndLine
*/
public int getLine() {
- return bufline[bufpos];
+ return bufline[bufpos];
}
+ /** Get token end column number. */
public int getEndColumn() {
- return bufcolumn[bufpos];
+ return bufcolumn[bufpos];
}
+ /** Get token end line number. */
public int getEndLine() {
return bufline[bufpos];
}
+ /** Get token beginning column number. */
public int getBeginColumn() {
- return bufcolumn[tokenBegin];
+ return bufcolumn[tokenBegin];
}
+ /** Get token beginning line number. */
public int getBeginLine() {
- return bufline[tokenBegin];
+ return bufline[tokenBegin];
}
+/** Backup a number of characters. */
public void backup(int amount) {
inBuf += amount;
if ((bufpos -= amount) < 0)
- bufpos += bufsize;
+ bufpos += bufsize;
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
@@ -267,16 +281,20 @@ public class SimpleCharStream
bufcolumn = new int[buffersize];
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn)
{
- this(dstream, startline, startcolumn, 4096);
+ this(dstream, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream)
{
- this(dstream, 1, 1, 4096);
+ this(dstream, 1, 1, 4096);
}
+
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
@@ -296,111 +314,128 @@ public class SimpleCharStream
bufpos = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn)
{
- ReInit(dstream, startline, startcolumn, 4096);
+ ReInit(dstream, startline, startcolumn, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream)
{
- ReInit(dstream, 1, 1, 4096);
+ ReInit(dstream, 1, 1, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
- this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
- this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
- this(dstream, encoding, startline, startcolumn, 4096);
+ this(dstream, encoding, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn)
{
- this(dstream, startline, startcolumn, 4096);
+ this(dstream, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
- this(dstream, encoding, 1, 1, 4096);
+ this(dstream, encoding, 1, 1, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream)
{
- this(dstream, 1, 1, 4096);
+ this(dstream, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
- ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
- ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
- ReInit(dstream, encoding, 1, 1, 4096);
+ ReInit(dstream, encoding, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream)
{
- ReInit(dstream, 1, 1, 4096);
+ ReInit(dstream, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
- ReInit(dstream, encoding, startline, startcolumn, 4096);
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn)
{
- ReInit(dstream, startline, startcolumn, 4096);
+ ReInit(dstream, startline, startcolumn, 4096);
}
+ /** Get token literal value. */
public String GetImage()
{
- if (bufpos >= tokenBegin)
- return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
- else
- return new String(buffer, tokenBegin, bufsize - tokenBegin) +
- new String(buffer, 0, bufpos + 1);
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
}
+ /** Get the suffix. */
public char[] GetSuffix(int len)
{
- char[] ret = new char[len];
+ char[] ret = new char[len];
- if ((bufpos + 1) >= len)
- System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
- else
- {
- System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
- len - bufpos - 1);
- System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
- }
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
- return ret;
+ return ret;
}
+ /** Reset buffer when finished. */
public void Done()
{
- buffer = null;
- bufline = null;
- bufcolumn = null;
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
}
/**
@@ -408,47 +443,47 @@ public class SimpleCharStream
*/
public void adjustBeginLineColumn(int newLine, int newCol)
{
- int start = tokenBegin;
- int len;
+ int start = tokenBegin;
+ int len;
- if (bufpos >= tokenBegin)
- {
- len = bufpos - tokenBegin + inBuf + 1;
- }
- else
- {
- len = bufsize - tokenBegin + bufpos + 1 + inBuf;
- }
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
- int i = 0, j = 0, k = 0;
- int nextColDiff = 0, columnDiff = 0;
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
- while (i < len &&
- bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
- {
- bufline[j] = newLine;
- nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
- bufcolumn[j] = newCol + columnDiff;
- columnDiff = nextColDiff;
- i++;
- }
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
- if (i < len)
- {
- bufline[j] = newLine++;
- bufcolumn[j] = newCol + columnDiff;
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
- while (i++ < len)
- {
- if (bufline[j = start % bufsize] != bufline[++start % bufsize])
- bufline[j] = newLine++;
- else
- bufline[j] = newLine;
- }
- }
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
- line = bufline[j];
- column = bufcolumn[j];
+ line = bufline[j];
+ column = bufcolumn[j];
}
}
+/* JavaCC - OriginalChecksum=aa11a0881c952a5f8ec0ffbd5648e1c4 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java b/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java
index 9bf537e60..1847a3bc9 100644
--- a/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java
+++ b/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java
@@ -1,11 +1,14 @@
-/* Generated By:JJTree: Do not edit this line. SimpleNode.java */
-
+/* Generated By:JJTree: Do not edit this line. SimpleNode.java Version 4.3 */
+/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=org.apache.james.mime4j.field.address.parser.BaseNode,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package org.apache.james.mime4j.field.address.parser;
-public class SimpleNode extends org.apache.james.mime4j.field.address.parser.BaseNode implements Node {
+public
+class SimpleNode extends org.apache.james.mime4j.field.address.parser.BaseNode implements Node {
+
protected Node parent;
protected Node[] children;
protected int id;
+ protected Object value;
protected AddressListParser parser;
public SimpleNode(int i) {
@@ -22,7 +25,7 @@ public class SimpleNode extends org.apache.james.mime4j.field.address.parser.Bas
public void jjtClose() {
}
-
+
public void jjtSetParent(Node n) { parent = n; }
public Node jjtGetParent() { return parent; }
@@ -45,13 +48,18 @@ public class SimpleNode extends org.apache.james.mime4j.field.address.parser.Bas
return (children == null) ? 0 : children.length;
}
+ public void jjtSetValue(Object value) { this.value = value; }
+ public Object jjtGetValue() { return value; }
+
/** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
+ public Object jjtAccept(AddressListParserVisitor visitor, Object data)
+{
return visitor.visit(this, data);
}
/** Accept the visitor. **/
- public Object childrenAccept(AddressListParserVisitor visitor, Object data) {
+ public Object childrenAccept(AddressListParserVisitor visitor, Object data)
+{
if (children != null) {
for (int i = 0; i < children.length; ++i) {
children[i].jjtAccept(visitor, data);
@@ -76,12 +84,13 @@ public class SimpleNode extends org.apache.james.mime4j.field.address.parser.Bas
System.out.println(toString(prefix));
if (children != null) {
for (int i = 0; i < children.length; ++i) {
- SimpleNode n = (SimpleNode)children[i];
- if (n != null) {
- n.dump(prefix + " ");
- }
+ SimpleNode n = (SimpleNode)children[i];
+ if (n != null) {
+ n.dump(prefix + " ");
+ }
}
}
}
}
+/* JavaCC - OriginalChecksum=055879471a7647d34de4235b3186aa17 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/Token.java b/src/org/apache/james/mime4j/field/address/parser/Token.java
index 0228aac3e..97499f407 100644
--- a/src/org/apache/james/mime4j/field/address/parser/Token.java
+++ b/src/org/apache/james/mime4j/field/address/parser/Token.java
@@ -1,26 +1,37 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.address.parser;
/**
* Describes the input token stream.
*/
-public class Token {
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
/**
* An integer that describes the kind of this token. This numbering
@@ -29,12 +40,14 @@ public class Token {
*/
public int kind;
- /**
- * beginLine and beginColumn describe the position of the first character
- * of this token; endLine and endColumn describe the position of the
- * last character of this token.
- */
- public int beginLine, beginColumn, endLine, endColumn;
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
/**
* The string image of the token.
@@ -65,12 +78,46 @@ public class Token {
*/
public Token specialToken;
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
/**
* Returns the image.
*/
public String toString()
{
- return image;
+ return image;
}
/**
@@ -78,19 +125,25 @@ public class Token {
* can create and return subclass objects based on the value of ofKind.
* Simply add the cases to the switch for all those special cases.
* For example, if you have a subclass of Token called IDToken that
- * you want to create if ofKind is ID, simlpy add something like :
+ * you want to create if ofKind is ID, simply add something like :
*
- * case MyParserConstants.ID : return new IDToken();
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
*
* to the following switch statement. Then you can cast matchedToken
- * variable to the appropriate type and use it in your lexical actions.
+ * variable to the appropriate type and use sit in your lexical actions.
*/
- public static final Token newToken(int ofKind)
+ public static Token newToken(int ofKind, String image)
{
- switch(ofKind)
- {
- default : return new Token();
- }
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
}
}
+/* JavaCC - OriginalChecksum=a51dc23d1faa88394342107e41df07b3 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java
index c06a44cf3..b9302c43d 100644
--- a/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java
+++ b/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java
@@ -1,148 +1,165 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+/****************************************************************
+ * 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.address.parser;
+/** Token Manager Error. */
public class TokenMgrError extends Error
{
- /*
- * Ordinals for various reasons why an Error of this type can be thrown.
- */
- /**
- * Lexical error occured.
- */
- static final int LEXICAL_ERROR = 0;
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
- /**
- * An attempt wass made to create a second instance of a static token manager.
- */
- static final int STATIC_LEXER_ERROR = 1;
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
- /**
- * Tried to change to an invalid lexical state.
- */
- static final int INVALID_LEXICAL_STATE = 2;
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
- /**
- * Detected (and bailed out of) an infinite loop in the token manager.
- */
- static final int LOOP_DETECTED = 3;
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
- /**
- * Indicates the reason why the exception is thrown. It will have
- * one of the above 4 values.
- */
- int errorCode;
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
- /**
- * Replaces unprintable characters by their espaced (or unicode escaped)
- * equivalents in the given string
- */
- protected static final String addEscapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
}
- return retval.toString();
- }
+ }
+ return retval.toString();
+ }
- /**
- * Returns a detailed message for the Error when it is thrown by the
- * token manager to indicate a lexical error.
- * Parameters :
- * EOFSeen : indicates if EOF caused the lexicl error
- * curLexState : lexical state in which this error occured
- * errorLine : line number when the error occured
- * errorColumn : column number when the error occured
- * errorAfter : prefix that was seen before this error occured
- * curchar : the offending character
- * Note: You can customize the lexical error message by modifying this method.
- */
- protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
- return("Lexical error at line " +
- errorLine + ", column " +
- errorColumn + ". Encountered: " +
- (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
- "after : \"" + addEscapes(errorAfter) + "\"");
- }
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
- /**
- * You can also modify the body of this method to customize your error messages.
- * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
- * of end-users concern, so you can return something like :
- *
- * "Internal Error : Please file a bug report .... "
- *
- * from this method for such cases in the release version of your parser.
- */
- public String getMessage() {
- return super.getMessage();
- }
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
- /*
- * Constructors of various flavors follow.
- */
+ /*
+ * Constructors of various flavors follow.
+ */
- public TokenMgrError() {
- }
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
- public TokenMgrError(String message, int reason) {
- super(message);
- errorCode = reason;
- }
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
- public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
- this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
- }
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
}
+/* JavaCC - OriginalChecksum=c00a20fac1340b0977b68c98d352e42d (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/contentdisposition/parser/ContentDispositionParser.java b/src/org/apache/james/mime4j/field/contentdisposition/parser/ContentDispositionParser.java
new file mode 100644
index 000000000..72a346135
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/contentdisposition/parser/ContentDispositionParser.java
@@ -0,0 +1,292 @@
+/* Generated By:JavaCC: Do not edit this line. ContentDispositionParser.java */
+/****************************************************************
+ * 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.contentdisposition.parser;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class ContentDispositionParser implements ContentDispositionParserConstants {
+
+ private String dispositionType;
+ private List paramNames = new ArrayList();
+ private List paramValues = new ArrayList();
+
+ public String getDispositionType() {
+ return dispositionType;
+ }
+
+ public List getParamNames() {
+ return paramNames;
+ }
+
+ public List getParamValues() {
+ return paramValues;
+ }
+
+ public static void main(String args[]) throws ParseException {
+ while (true) {
+ try {
+ ContentDispositionParser parser = new ContentDispositionParser(
+ System.in);
+ parser.parseLine();
+ } catch (Exception x) {
+ x.printStackTrace();
+ return;
+ }
+ }
+ }
+
+ final public void parseLine() throws ParseException {
+ parse();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case 1:
+ jj_consume_token(1);
+ break;
+ default:
+ jj_la1[0] = jj_gen;
+ ;
+ }
+ jj_consume_token(2);
+ }
+
+ final public void parseAll() throws ParseException {
+ parse();
+ jj_consume_token(0);
+ }
+
+ final public void parse() throws ParseException {
+ Token dispositionType;
+ dispositionType = jj_consume_token(ATOKEN);
+ this.dispositionType = dispositionType.image;
+ label_1:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case 3:
+ ;
+ break;
+ default:
+ jj_la1[1] = jj_gen;
+ break label_1;
+ }
+ jj_consume_token(3);
+ parameter();
+ }
+ }
+
+ final public void parameter() throws ParseException {
+ Token attrib;
+ String val;
+ attrib = jj_consume_token(ATOKEN);
+ jj_consume_token(4);
+ val = value();
+ paramNames.add(attrib.image);
+ paramValues.add(val);
+ }
+
+ final public String value() throws ParseException {
+ Token t;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case ATOKEN:
+ t = jj_consume_token(ATOKEN);
+ break;
+ case DIGITS:
+ t = jj_consume_token(DIGITS);
+ break;
+ case QUOTEDSTRING:
+ t = jj_consume_token(QUOTEDSTRING);
+ break;
+ default:
+ jj_la1[2] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ {if (true) return t.image;}
+ throw new Error("Missing return statement in function");
+ }
+
+ /** Generated Token Manager. */
+ public ContentDispositionParserTokenManager token_source;
+ SimpleCharStream jj_input_stream;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
+ private int jj_ntk;
+ private int jj_gen;
+ final private int[] jj_la1 = new int[3];
+ static private int[] jj_la1_0;
+ static {
+ jj_la1_init_0();
+ }
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0x2,0x8,0x1c0000,};
+ }
+
+ /** Constructor with InputStream. */
+ public ContentDispositionParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+ /** Constructor with InputStream and supplied encoding */
+ public ContentDispositionParser(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source = new ContentDispositionParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream) {
+ ReInit(stream, null);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor. */
+ public ContentDispositionParser(java.io.Reader stream) {
+ jj_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new ContentDispositionParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader stream) {
+ jj_input_stream.ReInit(stream, 1, 1);
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor with generated Token Manager. */
+ public ContentDispositionParser(ContentDispositionParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(ContentDispositionParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ if (token.kind == kind) {
+ jj_gen++;
+ return token;
+ }
+ token = oldToken;
+ jj_kind = kind;
+ throw generateParseException();
+ }
+
+
+/** Get the next Token. */
+ final public Token getNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ jj_gen++;
+ return token;
+ }
+
+/** Get the specific Token. */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk() {
+ if ((jj_nt=token.next) == null)
+ return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+ else
+ return (jj_ntk = jj_nt.kind);
+ }
+
+ private java.util.List jj_expentries = new java.util.ArrayList();
+ private int[] jj_expentry;
+ private int jj_kind = -1;
+
+ /** Generate ParseException. */
+ public ParseException generateParseException() {
+ jj_expentries.clear();
+ boolean[] la1tokens = new boolean[23];
+ if (jj_kind >= 0) {
+ la1tokens[jj_kind] = true;
+ jj_kind = -1;
+ }
+ for (int i = 0; i < 3; i++) {
+ if (jj_la1[i] == jj_gen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jj_la1_0[i] & (1<",
+ "\"\\r\"",
+ "\"\\n\"",
+ "\";\"",
+ "\"=\"",
+ "",
+ "\"(\"",
+ "\")\"",
+ "",
+ "\"(\"",
+ "",
+ "",
+ "\"(\"",
+ "\")\"",
+ "",
+ "\"\\\"\"",
+ "",
+ "",
+ "\"\\\"\"",
+ "",
+ "",
+ "",
+ "",
+ };
+
+}
diff --git a/src/org/apache/james/mime4j/field/contentdisposition/parser/ContentDispositionParserTokenManager.java b/src/org/apache/james/mime4j/field/contentdisposition/parser/ContentDispositionParserTokenManager.java
new file mode 100644
index 000000000..08dfd51dc
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/contentdisposition/parser/ContentDispositionParserTokenManager.java
@@ -0,0 +1,857 @@
+/* Generated By:JavaCC: Do not edit this line. ContentDispositionParserTokenManager.java */
+/****************************************************************
+ * 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.contentdisposition.parser;
+import java.util.List;
+import java.util.ArrayList;
+
+/** Token Manager. */
+public class ContentDispositionParserTokenManager implements ContentDispositionParserConstants
+{
+ // Keeps track of how many levels of comment nesting
+ // we've encountered. This is only used when the 2nd
+ // level is reached, for example ((this)), not (this).
+ // This is because the outermost level must be treated
+ // specially anyway, because the outermost ")" has a
+ // different token type than inner ")" instances.
+ static int commentNest;
+
+ /** Debug output. */
+ public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
+ public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+ return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private int jjStopAtPos(int pos, int kind)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_0()
+{
+ switch(curChar)
+ {
+ case 10:
+ return jjStartNfaWithStates_0(0, 2, 2);
+ case 13:
+ return jjStartNfaWithStates_0(0, 1, 2);
+ case 34:
+ return jjStopAtPos(0, 15);
+ case 40:
+ return jjStopAtPos(0, 6);
+ case 59:
+ return jjStopAtPos(0, 3);
+ case 61:
+ return jjStopAtPos(0, 4);
+ default :
+ return jjMoveNfa_0(3, 0);
+ }
+}
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return pos + 1; }
+ return jjMoveNfa_0(state, pos + 1);
+}
+static final long[] jjbitVec0 = {
+ 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_0(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 3:
+ if ((0x3ff6cfafffffdffL & l) != 0L)
+ {
+ if (kind > 20)
+ kind = 20;
+ jjCheckNAdd(2);
+ }
+ else if ((0x100000200L & l) != 0L)
+ {
+ if (kind > 5)
+ kind = 5;
+ jjCheckNAdd(0);
+ }
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 19)
+ kind = 19;
+ jjCheckNAdd(1);
+ }
+ break;
+ case 0:
+ if ((0x100000200L & l) == 0L)
+ break;
+ kind = 5;
+ jjCheckNAdd(0);
+ break;
+ case 1:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 19)
+ kind = 19;
+ jjCheckNAdd(1);
+ break;
+ case 2:
+ if ((0x3ff6cfafffffdffL & l) == 0L)
+ break;
+ if (kind > 20)
+ kind = 20;
+ jjCheckNAdd(2);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 3:
+ case 2:
+ if ((0xffffffffc7fffffeL & l) == 0L)
+ break;
+ kind = 20;
+ jjCheckNAdd(2);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 3:
+ case 2:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 20)
+ kind = 20;
+ jjCheckNAdd(2);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_1(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_1(int pos, long active0)
+{
+ return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_1()
+{
+ switch(curChar)
+ {
+ case 40:
+ return jjStopAtPos(0, 9);
+ case 41:
+ return jjStopAtPos(0, 7);
+ default :
+ return jjMoveNfa_1(0, 0);
+ }
+}
+private int jjMoveNfa_1(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 10)
+ kind = 10;
+ break;
+ case 1:
+ if (kind > 8)
+ kind = 8;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 10)
+ kind = 10;
+ if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 8)
+ kind = 8;
+ break;
+ case 2:
+ if (kind > 10)
+ kind = 10;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 10)
+ kind = 10;
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 8)
+ kind = 8;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_3(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_3(int pos, long active0)
+{
+ return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_3()
+{
+ switch(curChar)
+ {
+ case 34:
+ return jjStopAtPos(0, 18);
+ default :
+ return jjMoveNfa_3(0, 0);
+ }
+}
+private int jjMoveNfa_3(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ case 2:
+ if ((0xfffffffbffffffffL & l) == 0L)
+ break;
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(2);
+ break;
+ case 1:
+ if (kind > 16)
+ kind = 16;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((0xffffffffefffffffL & l) != 0L)
+ {
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(2);
+ }
+ else if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 16)
+ kind = 16;
+ break;
+ case 2:
+ if ((0xffffffffefffffffL & l) == 0L)
+ break;
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(2);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ case 2:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(2);
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 16)
+ kind = 16;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_2(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_2(int pos, long active0)
+{
+ return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_2()
+{
+ switch(curChar)
+ {
+ case 40:
+ return jjStopAtPos(0, 12);
+ case 41:
+ return jjStopAtPos(0, 13);
+ default :
+ return jjMoveNfa_2(0, 0);
+ }
+}
+private int jjMoveNfa_2(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 14)
+ kind = 14;
+ break;
+ case 1:
+ if (kind > 11)
+ kind = 11;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 14)
+ kind = 14;
+ if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 11)
+ kind = 11;
+ break;
+ case 2:
+ if (kind > 14)
+ kind = 14;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 14)
+ kind = 14;
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 11)
+ kind = 11;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+static final int[] jjnextStates = {
+};
+
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", "\15", "\12", "\73", "\75", null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, };
+
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+ "DEFAULT",
+ "INCOMMENT",
+ "NESTED_COMMENT",
+ "INQUOTEDSTRING",
+};
+
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+ -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1,
+};
+static final long[] jjtoToken = {
+ 0x1c001fL,
+};
+static final long[] jjtoSkip = {
+ 0xa0L,
+};
+static final long[] jjtoSpecial = {
+ 0x20L,
+};
+static final long[] jjtoMore = {
+ 0x3ff40L,
+};
+protected SimpleCharStream input_stream;
+private final int[] jjrounds = new int[3];
+private final int[] jjstateSet = new int[6];
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
+protected char curChar;
+/** Constructor. */
+public ContentDispositionParserTokenManager(SimpleCharStream stream){
+ if (SimpleCharStream.staticFlag)
+ throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+ input_stream = stream;
+}
+
+/** Constructor. */
+public ContentDispositionParserTokenManager(SimpleCharStream stream, int lexState){
+ this(stream);
+ SwitchTo(lexState);
+}
+
+/** Reinitialise parser. */
+public void ReInit(SimpleCharStream stream)
+{
+ jjmatchedPos = jjnewStateCnt = 0;
+ curLexState = defaultLexState;
+ input_stream = stream;
+ ReInitRounds();
+}
+private void ReInitRounds()
+{
+ int i;
+ jjround = 0x80000001;
+ for (i = 3; i-- > 0;)
+ jjrounds[i] = 0x80000000;
+}
+
+/** Reinitialise parser. */
+public void ReInit(SimpleCharStream stream, int lexState)
+{
+ ReInit(stream);
+ SwitchTo(lexState);
+}
+
+/** Switch to specified lex state. */
+public void SwitchTo(int lexState)
+{
+ if (lexState >= 4 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+ else
+ curLexState = lexState;
+}
+
+protected Token jjFillToken()
+{
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
+ String im = jjstrLiteralImages[jjmatchedKind];
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
+ return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+/** Get the next Token. */
+public Token getNextToken()
+{
+ Token specialToken = null;
+ Token matchedToken;
+ int curPos = 0;
+
+ EOFLoop :
+ for (;;)
+ {
+ try
+ {
+ curChar = input_stream.BeginToken();
+ }
+ catch(java.io.IOException e)
+ {
+ jjmatchedKind = 0;
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+ image = jjimage;
+ image.setLength(0);
+ jjimageLen = 0;
+
+ for (;;)
+ {
+ switch(curLexState)
+ {
+ case 0:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_0();
+ break;
+ case 1:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_1();
+ break;
+ case 2:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_2();
+ break;
+ case 3:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_3();
+ break;
+ }
+ if (jjmatchedKind != 0x7fffffff)
+ {
+ if (jjmatchedPos + 1 < curPos)
+ input_stream.backup(curPos - jjmatchedPos - 1);
+ if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ TokenLexicalActions(matchedToken);
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ return matchedToken;
+ }
+ else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ if (specialToken == null)
+ specialToken = matchedToken;
+ else
+ {
+ matchedToken.specialToken = specialToken;
+ specialToken = (specialToken.next = matchedToken);
+ }
+ }
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ continue EOFLoop;
+ }
+ MoreLexicalActions();
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ curPos = 0;
+ jjmatchedKind = 0x7fffffff;
+ try {
+ curChar = input_stream.readChar();
+ continue;
+ }
+ catch (java.io.IOException e1) { }
+ }
+ int error_line = input_stream.getEndLine();
+ int error_column = input_stream.getEndColumn();
+ String error_after = null;
+ boolean EOFSeen = false;
+ try { input_stream.readChar(); input_stream.backup(1); }
+ catch (java.io.IOException e1) {
+ EOFSeen = true;
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ error_line++;
+ error_column = 0;
+ }
+ else
+ error_column++;
+ }
+ if (!EOFSeen) {
+ input_stream.backup(1);
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ }
+ throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+ }
+ }
+}
+
+void MoreLexicalActions()
+{
+ jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
+ switch(jjmatchedKind)
+ {
+ case 8 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ case 9 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ commentNest = 1;
+ break;
+ case 11 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ case 12 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ ++commentNest;
+ break;
+ case 13 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
+ break;
+ case 15 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 1);
+ break;
+ case 16 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ default :
+ break;
+ }
+}
+void TokenLexicalActions(Token matchedToken)
+{
+ switch(jjmatchedKind)
+ {
+ case 18 :
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ matchedToken.image = image.substring(0, image.length() - 1);
+ break;
+ default :
+ break;
+ }
+}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
+}
diff --git a/src/org/apache/james/mime4j/field/contentdisposition/parser/ParseException.java b/src/org/apache/james/mime4j/field/contentdisposition/parser/ParseException.java
new file mode 100644
index 000000000..ca3278dec
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/contentdisposition/parser/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************
+ * 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.contentdisposition.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * This constructor is used by the method "generateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "tokenImage" set. The boolean
+ * flag "specialConstructor" is also set to true to indicate that
+ * this constructor was used to create this object.
+ * This constructor calls its super class with the empty string
+ * to force the "toString" method of parent class "Throwable" to
+ * print the error message in the form:
+ * ParseException:
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ String[] tokenImageVal
+ )
+ {
+ super("");
+ specialConstructor = true;
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Throwable". The fields "errorToken",
+ * "expectedTokenSequences", and "tokenImage" do not contain
+ * relevant information. The JavaCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() {
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
+ specialConstructor = false;
+ }
+
+ public ParseException(String message) {
+ super(message);
+ specialConstructor = false;
+ }
+
+ /**
+ * This variable determines which constructor was used to create
+ * this object and thereby affects the semantics of the
+ * "getMessage" method (see below).
+ */
+ protected boolean specialConstructor;
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "tokenImage" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public String[] tokenImage;
+
+ /**
+ * This method has the standard behavior when this object has been
+ * created using the standard constructors. Otherwise, it uses
+ * "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser), then this method is called during the printing
+ * of the final stack trace, and hence the correct error message
+ * gets displayed.
+ */
+ public String getMessage() {
+ if (!specialConstructor) {
+ return super.getMessage();
+ }
+ StringBuffer expected = new StringBuffer();
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.length; i++) {
+ if (maxSize < expectedTokenSequences[i].length) {
+ maxSize = expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+ expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+ expected.append("...");
+ }
+ expected.append(eol).append(" ");
+ }
+ String retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0) retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += add_escapes(tok.image);
+ tok = tok.next;
+ }
+ retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + eol;
+ if (expectedTokenSequences.length == 1) {
+ retval += "Was expecting:" + eol + " ";
+ } else {
+ retval += "Was expecting one of:" + eol + " ";
+ }
+ retval += expected.toString();
+ return retval;
+ }
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected String eol = System.getProperty("line.separator", "\n");
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ protected String add_escapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/contentdisposition/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/contentdisposition/parser/SimpleCharStream.java
new file mode 100644
index 000000000..92d2a4d5a
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/contentdisposition/parser/SimpleCharStream.java
@@ -0,0 +1,489 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.contentdisposition.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+ public static final boolean staticFlag = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+/** Position in buffer. */
+ public int bufpos = -1;
+ protected int bufline[];
+ protected int bufcolumn[];
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected boolean prevCharIsCR = false;
+ protected boolean prevCharIsLF = false;
+
+ protected java.io.Reader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+ protected int tabSize = 8;
+
+ protected void setTabSize(int i) { tabSize = i; }
+ protected int getTabSize(int i) { return tabSize; }
+
+
+ protected void ExpandBuff(boolean wrapAround)
+ {
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
+
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
+
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() throws java.io.IOException
+ {
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
+ {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ }
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+/** Start. */
+ public char BeginToken() throws java.io.IOException
+ {
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
+
+ return c;
+ }
+
+ protected void UpdateLineColumn(char c)
+ {
+ column++;
+
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
+ line += (column = 1);
+ }
+
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+/** Read a character. */
+ public char readChar() throws java.io.IOException
+ {
+ if (inBuf > 0)
+ {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return c;
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndColumn
+ */
+
+ public int getColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndLine
+ */
+
+ public int getLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token end column number. */
+ public int getEndColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ /** Get token end line number. */
+ public int getEndLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token beginning column number. */
+ public int getBeginColumn() {
+ return bufcolumn[tokenBegin];
+ }
+
+ /** Get token beginning line number. */
+ public int getBeginLine() {
+ return bufline[tokenBegin];
+ }
+
+/** Backup a number of characters. */
+ public void backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.length)
+ {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+ /** Get token literal value. */
+ public String GetImage()
+ {
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
+ }
+
+ /** Get the suffix. */
+ public char[] GetSuffix(int len)
+ {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ /** Reset buffer when finished. */
+ public void Done()
+ {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /**
+ * Method to adjust line and column numbers for the start of a token.
+ */
+ public void adjustBeginLineColumn(int newLine, int newCol)
+ {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+
+}
+/* JavaCC - OriginalChecksum=3a0a96dd40a434f5b242b9ed9202faa4 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/contentdisposition/parser/Token.java b/src/org/apache/james/mime4j/field/contentdisposition/parser/Token.java
new file mode 100644
index 000000000..26ff91167
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/contentdisposition/parser/Token.java
@@ -0,0 +1,149 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.contentdisposition.parser;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * An integer that describes the kind of this token. This numbering
+ * system is determined by JavaCCParser, and a table of these numbers is
+ * stored in the file ...Constants.java.
+ */
+ public int kind;
+
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
+
+ /**
+ * The string image of the token.
+ */
+ public String image;
+
+ /**
+ * A reference to the next regular (non-special) token from the input
+ * stream. If this is the last token from the input stream, or if the
+ * token manager has not read tokens beyond this one, this field is
+ * set to null. This is true only if this token is also a regular
+ * token. Otherwise, see below for a description of the contents of
+ * this field.
+ */
+ public Token next;
+
+ /**
+ * This field is used to access special tokens that occur prior to this
+ * token, but after the immediately preceding regular (non-special) token.
+ * If there are no such special tokens, this field is set to null.
+ * When there are more than one such special token, this field refers
+ * to the last of these special tokens, which in turn refers to the next
+ * previous special token through its specialToken field, and so on
+ * until the first special token (whose specialToken field is null).
+ * The next fields of special tokens refer to other special tokens that
+ * immediately follow it (without an intervening regular token). If there
+ * is no such token, this field is null.
+ */
+ public Token specialToken;
+
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
+ /**
+ * Returns the image.
+ */
+ public String toString()
+ {
+ return image;
+ }
+
+ /**
+ * Returns a new Token object, by default. However, if you want, you
+ * can create and return subclass objects based on the value of ofKind.
+ * Simply add the cases to the switch for all those special cases.
+ * For example, if you have a subclass of Token called IDToken that
+ * you want to create if ofKind is ID, simply add something like :
+ *
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
+ *
+ * to the following switch statement. Then you can cast matchedToken
+ * variable to the appropriate type and use sit in your lexical actions.
+ */
+ public static Token newToken(int ofKind, String image)
+ {
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
+ }
+
+}
+/* JavaCC - OriginalChecksum=b1ee9aaf7cbe47fcd350a0df848362b5 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/contentdisposition/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/contentdisposition/parser/TokenMgrError.java
new file mode 100644
index 000000000..a2712abe3
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/contentdisposition/parser/TokenMgrError.java
@@ -0,0 +1,165 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+/****************************************************************
+ * 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.contentdisposition.parser;
+
+/** Token Manager Error. */
+public class TokenMgrError extends Error
+{
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
+
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
+
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
+
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
+
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
+
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
+
+ /*
+ * Constructors of various flavors follow.
+ */
+
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
+
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
+
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
+}
+/* JavaCC - OriginalChecksum=9fa2b884a567f978be9291126c2a21c0 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java
index 64e829a51..32a9b65b6 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java
@@ -1,34 +1,38 @@
/* Generated By:JavaCC: Do not edit this line. ContentTypeParser.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.contenttype.parser;
+import java.util.List;
import java.util.ArrayList;
public class ContentTypeParser implements ContentTypeParserConstants {
private String type;
private String subtype;
- private ArrayList paramNames = new ArrayList();
- private ArrayList paramValues = new ArrayList();
+ private List paramNames = new ArrayList();
+ private List paramValues = new ArrayList();
public String getType() { return type; }
public String getSubType() { return subtype; }
- public ArrayList getParamNames() { return paramNames; }
- public ArrayList getParamValues() { return paramValues; }
+ public List getParamNames() { return paramNames; }
+ public List getParamValues() { return paramValues; }
public static void main(String args[]) throws ParseException {
while (true) {
@@ -99,6 +103,9 @@ public class ContentTypeParser implements ContentTypeParserConstants {
case ATOKEN:
t = jj_consume_token(ATOKEN);
break;
+ case DIGITS:
+ t = jj_consume_token(DIGITS);
+ break;
case QUOTEDSTRING:
t = jj_consume_token(QUOTEDSTRING);
break;
@@ -111,23 +118,29 @@ public class ContentTypeParser implements ContentTypeParserConstants {
throw new Error("Missing return statement in function");
}
+ /** Generated Token Manager. */
public ContentTypeParserTokenManager token_source;
SimpleCharStream jj_input_stream;
- public Token token, jj_nt;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
private int jj_ntk;
private int jj_gen;
final private int[] jj_la1 = new int[3];
static private int[] jj_la1_0;
static {
- jj_la1_0();
+ jj_la1_init_0();
}
- private static void jj_la1_0() {
- jj_la1_0 = new int[] {0x2,0x10,0x280000,};
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0x2,0x10,0x380000,};
}
+ /** Constructor with InputStream. */
public ContentTypeParser(java.io.InputStream stream) {
this(stream, null);
}
+ /** Constructor with InputStream and supplied encoding */
public ContentTypeParser(java.io.InputStream stream, String encoding) {
try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
token_source = new ContentTypeParserTokenManager(jj_input_stream);
@@ -137,9 +150,11 @@ public class ContentTypeParser implements ContentTypeParserConstants {
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream stream) {
ReInit(stream, null);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream stream, String encoding) {
try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
token_source.ReInit(jj_input_stream);
@@ -149,6 +164,7 @@ public class ContentTypeParser implements ContentTypeParserConstants {
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
}
+ /** Constructor. */
public ContentTypeParser(java.io.Reader stream) {
jj_input_stream = new SimpleCharStream(stream, 1, 1);
token_source = new ContentTypeParserTokenManager(jj_input_stream);
@@ -158,6 +174,7 @@ public class ContentTypeParser implements ContentTypeParserConstants {
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader stream) {
jj_input_stream.ReInit(stream, 1, 1);
token_source.ReInit(jj_input_stream);
@@ -167,6 +184,7 @@ public class ContentTypeParser implements ContentTypeParserConstants {
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
}
+ /** Constructor with generated Token Manager. */
public ContentTypeParser(ContentTypeParserTokenManager tm) {
token_source = tm;
token = new Token();
@@ -175,6 +193,7 @@ public class ContentTypeParser implements ContentTypeParserConstants {
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
}
+ /** Reinitialise. */
public void ReInit(ContentTypeParserTokenManager tm) {
token_source = tm;
token = new Token();
@@ -183,7 +202,7 @@ public class ContentTypeParser implements ContentTypeParserConstants {
for (int i = 0; i < 3; i++) jj_la1[i] = -1;
}
- final private Token jj_consume_token(int kind) throws ParseException {
+ private Token jj_consume_token(int kind) throws ParseException {
Token oldToken;
if ((oldToken = token).next != null) token = token.next;
else token = token.next = token_source.getNextToken();
@@ -197,6 +216,8 @@ public class ContentTypeParser implements ContentTypeParserConstants {
throw generateParseException();
}
+
+/** Get the next Token. */
final public Token getNextToken() {
if (token.next != null) token = token.next;
else token = token.next = token_source.getNextToken();
@@ -205,6 +226,7 @@ public class ContentTypeParser implements ContentTypeParserConstants {
return token;
}
+/** Get the specific Token. */
final public Token getToken(int index) {
Token t = token;
for (int i = 0; i < index; i++) {
@@ -214,23 +236,21 @@ public class ContentTypeParser implements ContentTypeParserConstants {
return t;
}
- final private int jj_ntk() {
+ private int jj_ntk() {
if ((jj_nt=token.next) == null)
return (jj_ntk = (token.next=token_source.getNextToken()).kind);
else
return (jj_ntk = jj_nt.kind);
}
- private java.util.Vector jj_expentries = new java.util.Vector();
+ private java.util.List jj_expentries = new java.util.ArrayList();
private int[] jj_expentry;
private int jj_kind = -1;
+ /** Generate ParseException. */
public ParseException generateParseException() {
- jj_expentries.removeAllElements();
+ jj_expentries.clear();
boolean[] la1tokens = new boolean[24];
- for (int i = 0; i < 24; i++) {
- la1tokens[i] = false;
- }
if (jj_kind >= 0) {
la1tokens[jj_kind] = true;
jj_kind = -1;
@@ -248,19 +268,21 @@ public class ContentTypeParser implements ContentTypeParserConstants {
if (la1tokens[i]) {
jj_expentry = new int[1];
jj_expentry[0] = i;
- jj_expentries.addElement(jj_expentry);
+ jj_expentries.add(jj_expentry);
}
}
int[][] exptokseq = new int[jj_expentries.size()][];
for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = (int[])jj_expentries.elementAt(i);
+ exptokseq[i] = jj_expentries.get(i);
}
return new ParseException(token, exptokseq, tokenImage);
}
+ /** Enable tracing. */
final public void enable_tracing() {
}
+ /** Disable tracing. */
final public void disable_tracing() {
}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java
index 8a763287d..e4d06265d 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java
@@ -1,37 +1,58 @@
/* Generated By:JavaCC: Do not edit this line. ContentTypeParserConstants.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.contenttype.parser;
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
public interface ContentTypeParserConstants {
+ /** End of File. */
int EOF = 0;
+ /** RegularExpression Id. */
int WS = 6;
+ /** RegularExpression Id. */
int COMMENT = 8;
+ /** RegularExpression Id. */
int QUOTEDSTRING = 19;
+ /** RegularExpression Id. */
int DIGITS = 20;
+ /** RegularExpression Id. */
int ATOKEN = 21;
+ /** RegularExpression Id. */
int QUOTEDPAIR = 22;
+ /** RegularExpression Id. */
int ANY = 23;
+ /** Lexical state. */
int DEFAULT = 0;
+ /** Lexical state. */
int INCOMMENT = 1;
+ /** Lexical state. */
int NESTED_COMMENT = 2;
+ /** Lexical state. */
int INQUOTEDSTRING = 3;
+ /** Literal token values. */
String[] tokenImage = {
"",
"\"\\r\"",
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java
index 05d940db5..175d660c4 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java
@@ -1,22 +1,27 @@
/* Generated By:JavaCC: Do not edit this line. ContentTypeParserTokenManager.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.contenttype.parser;
+import java.util.List;
import java.util.ArrayList;
+/** Token Manager. */
public class ContentTypeParserTokenManager implements ContentTypeParserConstants
{
// Keeps track of how many levels of comment nesting
@@ -26,7 +31,10 @@ public class ContentTypeParserTokenManager implements ContentTypeParserConstants
// specially anyway, because the outermost ")" has a
// different token type than inner ")" instances.
static int commentNest;
+
+ /** Debug output. */
public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
private final int jjStopStringLiteralDfa_0(int pos, long active0)
{
@@ -40,21 +48,13 @@ private final int jjStartNfa_0(int pos, long active0)
{
return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
}
-private final int jjStopAtPos(int pos, int kind)
+private int jjStopAtPos(int pos, int kind)
{
jjmatchedKind = kind;
jjmatchedPos = pos;
return pos + 1;
}
-private final int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_0(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_0()
+private int jjMoveStringLiteralDfa0_0()
{
switch(curChar)
{
@@ -76,47 +76,24 @@ private final int jjMoveStringLiteralDfa0_0()
return jjMoveNfa_0(3, 0);
}
}
-private final void jjCheckNAdd(int state)
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
{
- if (jjrounds[state] != jjround)
- {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
- }
-}
-private final void jjAddStates(int start, int end)
-{
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
-}
-private final void jjCheckNAddTwoStates(int state1, int state2)
-{
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
-}
-private final void jjCheckNAddStates(int start, int end)
-{
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
-}
-private final void jjCheckNAddStates(int start)
-{
- jjCheckNAdd(jjnextStates[start]);
- jjCheckNAdd(jjnextStates[start + 1]);
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return pos + 1; }
+ return jjMoveNfa_0(state, pos + 1);
}
static final long[] jjbitVec0 = {
0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
};
-private final int jjMoveNfa_0(int startState, int curPos)
+private int jjMoveNfa_0(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -124,7 +101,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -175,7 +152,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -194,7 +171,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -235,15 +212,7 @@ private final int jjStartNfa_1(int pos, long active0)
{
return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_1(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_1(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_1()
+private int jjMoveStringLiteralDfa0_1()
{
switch(curChar)
{
@@ -255,14 +224,13 @@ private final int jjMoveStringLiteralDfa0_1()
return jjMoveNfa_1(0, 0);
}
}
-private final int jjMoveNfa_1(int startState, int curPos)
+private int jjMoveNfa_1(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -270,7 +238,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -289,7 +257,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -315,7 +283,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -356,15 +324,7 @@ private final int jjStartNfa_3(int pos, long active0)
{
return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_3(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_3(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_3()
+private int jjMoveStringLiteralDfa0_3()
{
switch(curChar)
{
@@ -374,14 +334,13 @@ private final int jjMoveStringLiteralDfa0_3()
return jjMoveNfa_3(0, 0);
}
}
-private final int jjMoveNfa_3(int startState, int curPos)
+private int jjMoveNfa_3(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -389,7 +348,7 @@ private final int jjMoveNfa_3(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -412,7 +371,7 @@ private final int jjMoveNfa_3(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -445,7 +404,7 @@ private final int jjMoveNfa_3(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -490,15 +449,7 @@ private final int jjStartNfa_2(int pos, long active0)
{
return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_2(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_2(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_2()
+private int jjMoveStringLiteralDfa0_2()
{
switch(curChar)
{
@@ -510,14 +461,13 @@ private final int jjMoveStringLiteralDfa0_2()
return jjMoveNfa_2(0, 0);
}
}
-private final int jjMoveNfa_2(int startState, int curPos)
+private int jjMoveNfa_2(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -525,7 +475,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -544,7 +494,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -570,7 +520,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -601,15 +551,21 @@ private final int jjMoveNfa_2(int startState, int curPos)
}
static final int[] jjnextStates = {
};
+
+/** Token literal values. */
public static final String[] jjstrLiteralImages = {
"", "\15", "\12", "\57", "\73", "\75", null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, };
+
+/** Lexer state names. */
public static final String[] lexStateNames = {
- "DEFAULT",
- "INCOMMENT",
- "NESTED_COMMENT",
- "INQUOTEDSTRING",
+ "DEFAULT",
+ "INCOMMENT",
+ "NESTED_COMMENT",
+ "INQUOTEDSTRING",
};
+
+/** Lex State array. */
public static final int[] jjnewLexState = {
-1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1,
};
@@ -628,19 +584,25 @@ static final long[] jjtoMore = {
protected SimpleCharStream input_stream;
private final int[] jjrounds = new int[3];
private final int[] jjstateSet = new int[6];
-StringBuffer image;
-int jjimageLen;
-int lengthOfMatch;
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
protected char curChar;
+/** Constructor. */
public ContentTypeParserTokenManager(SimpleCharStream stream){
if (SimpleCharStream.staticFlag)
throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
input_stream = stream;
}
+
+/** Constructor. */
public ContentTypeParserTokenManager(SimpleCharStream stream, int lexState){
this(stream);
SwitchTo(lexState);
}
+
+/** Reinitialise parser. */
public void ReInit(SimpleCharStream stream)
{
jjmatchedPos = jjnewStateCnt = 0;
@@ -648,18 +610,22 @@ public void ReInit(SimpleCharStream stream)
input_stream = stream;
ReInitRounds();
}
-private final void ReInitRounds()
+private void ReInitRounds()
{
int i;
jjround = 0x80000001;
for (i = 3; i-- > 0;)
jjrounds[i] = 0x80000000;
}
+
+/** Reinitialise parser. */
public void ReInit(SimpleCharStream stream, int lexState)
{
ReInit(stream);
SwitchTo(lexState);
}
+
+/** Switch to specified lex state. */
public void SwitchTo(int lexState)
{
if (lexState >= 4 || lexState < 0)
@@ -670,14 +636,25 @@ public void SwitchTo(int lexState)
protected Token jjFillToken()
{
- Token t = Token.newToken(jjmatchedKind);
- t.kind = jjmatchedKind;
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
String im = jjstrLiteralImages[jjmatchedKind];
- t.image = (im == null) ? input_stream.GetImage() : im;
- t.beginLine = input_stream.getBeginLine();
- t.beginColumn = input_stream.getBeginColumn();
- t.endLine = input_stream.getEndLine();
- t.endColumn = input_stream.getEndColumn();
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
return t;
}
@@ -688,28 +665,29 @@ int jjround;
int jjmatchedPos;
int jjmatchedKind;
+/** Get the next Token. */
public Token getNextToken()
{
- int kind;
Token specialToken = null;
Token matchedToken;
int curPos = 0;
EOFLoop :
for (;;)
- {
- try
- {
+ {
+ try
+ {
curChar = input_stream.BeginToken();
- }
+ }
catch(java.io.IOException e)
- {
+ {
jjmatchedKind = 0;
matchedToken = jjFillToken();
matchedToken.specialToken = specialToken;
return matchedToken;
}
- image = null;
+ image = jjimage;
+ image.setLength(0);
jjimageLen = 0;
for (;;)
@@ -808,55 +786,41 @@ void MoreLexicalActions()
switch(jjmatchedKind)
{
case 9 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 10 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
commentNest = 1;
break;
case 12 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 13 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
++commentNest;
break;
case 14 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
--commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
break;
case 16 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 1);
break;
case 17 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
- default :
+ default :
break;
}
}
@@ -865,13 +829,31 @@ void TokenLexicalActions(Token matchedToken)
switch(jjmatchedKind)
{
case 19 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
matchedToken.image = image.substring(0, image.length() - 1);
break;
- default :
+ default :
break;
}
}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java b/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java
index 2c5dc8275..3a4c67028 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java
@@ -1,19 +1,22 @@
/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.contenttype.parser;
/**
@@ -22,10 +25,15 @@ package org.apache.james.mime4j.field.contenttype.parser;
* calling the method generateParseException in the generated
* parser.
*
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
*/
-public class ParseException extends Exception {
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
/**
* This constructor is used by the method "generateParseException"
@@ -62,7 +70,12 @@ public class ParseException extends Exception {
*/
public ParseException() {
- super();
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
specialConstructor = false;
}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java
index c139e4f38..dd43e5ffe 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java
@@ -1,19 +1,23 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.contenttype.parser;
/**
@@ -23,10 +27,12 @@ package org.apache.james.mime4j.field.contenttype.parser;
public class SimpleCharStream
{
+/** Whether parser is static. */
public static final boolean staticFlag = false;
int bufsize;
int available;
int tokenBegin;
+/** Position in buffer. */
public int bufpos = -1;
protected int bufline[];
protected int bufcolumn[];
@@ -50,210 +56,218 @@ public class SimpleCharStream
protected void ExpandBuff(boolean wrapAround)
{
- char[] newbuffer = new char[bufsize + 2048];
- int newbufline[] = new int[bufsize + 2048];
- int newbufcolumn[] = new int[bufsize + 2048];
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
- try
- {
- if (wrapAround)
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- System.arraycopy(buffer, 0, newbuffer,
- bufsize - tokenBegin, bufpos);
- buffer = newbuffer;
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
- bufline = newbufline;
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
- bufcolumn = newbufcolumn;
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
- maxNextCharInd = (bufpos += (bufsize - tokenBegin));
- }
- else
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- buffer = newbuffer;
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- bufline = newbufline;
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- bufcolumn = newbufcolumn;
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
- maxNextCharInd = (bufpos -= tokenBegin);
- }
- }
- catch (Throwable t)
- {
- throw new Error(t.getMessage());
- }
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
- bufsize += 2048;
- available = bufsize;
- tokenBegin = 0;
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
}
protected void FillBuff() throws java.io.IOException
{
- if (maxNextCharInd == available)
- {
- if (available == bufsize)
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
{
- if (tokenBegin > 2048)
- {
- bufpos = maxNextCharInd = 0;
- available = tokenBegin;
- }
- else if (tokenBegin < 0)
- bufpos = maxNextCharInd = 0;
- else
- ExpandBuff(false);
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
}
- else if (available > tokenBegin)
- available = bufsize;
- else if ((tokenBegin - available) < 2048)
- ExpandBuff(true);
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
else
- available = tokenBegin;
- }
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
- int i;
- try {
- if ((i = inputStream.read(buffer, maxNextCharInd,
- available - maxNextCharInd)) == -1)
- {
- inputStream.close();
- throw new java.io.IOException();
- }
- else
- maxNextCharInd += i;
- return;
- }
- catch(java.io.IOException e) {
- --bufpos;
- backup(0);
- if (tokenBegin == -1)
- tokenBegin = bufpos;
- throw e;
- }
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
}
+/** Start. */
public char BeginToken() throws java.io.IOException
{
- tokenBegin = -1;
- char c = readChar();
- tokenBegin = bufpos;
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
- return c;
+ return c;
}
protected void UpdateLineColumn(char c)
{
- column++;
+ column++;
- if (prevCharIsLF)
- {
- prevCharIsLF = false;
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
line += (column = 1);
- }
- else if (prevCharIsCR)
- {
- prevCharIsCR = false;
- if (c == '\n')
- {
- prevCharIsLF = true;
- }
- else
- line += (column = 1);
- }
+ }
- switch (c)
- {
- case '\r' :
- prevCharIsCR = true;
- break;
- case '\n' :
- prevCharIsLF = true;
- break;
- case '\t' :
- column--;
- column += (tabSize - (column % tabSize));
- break;
- default :
- break;
- }
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
- bufline[bufpos] = line;
- bufcolumn[bufpos] = column;
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
}
+/** Read a character. */
public char readChar() throws java.io.IOException
{
- if (inBuf > 0)
- {
- --inBuf;
+ if (inBuf > 0)
+ {
+ --inBuf;
- if (++bufpos == bufsize)
- bufpos = 0;
+ if (++bufpos == bufsize)
+ bufpos = 0;
- return buffer[bufpos];
- }
+ return buffer[bufpos];
+ }
- if (++bufpos >= maxNextCharInd)
- FillBuff();
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
- char c = buffer[bufpos];
+ char c = buffer[bufpos];
- UpdateLineColumn(c);
- return (c);
+ UpdateLineColumn(c);
+ return c;
}
+ @Deprecated
/**
- * @deprecated
+ * @deprecated
* @see #getEndColumn
*/
public int getColumn() {
- return bufcolumn[bufpos];
+ return bufcolumn[bufpos];
}
+ @Deprecated
/**
- * @deprecated
+ * @deprecated
* @see #getEndLine
*/
public int getLine() {
- return bufline[bufpos];
+ return bufline[bufpos];
}
+ /** Get token end column number. */
public int getEndColumn() {
- return bufcolumn[bufpos];
+ return bufcolumn[bufpos];
}
+ /** Get token end line number. */
public int getEndLine() {
return bufline[bufpos];
}
+ /** Get token beginning column number. */
public int getBeginColumn() {
- return bufcolumn[tokenBegin];
+ return bufcolumn[tokenBegin];
}
+ /** Get token beginning line number. */
public int getBeginLine() {
- return bufline[tokenBegin];
+ return bufline[tokenBegin];
}
+/** Backup a number of characters. */
public void backup(int amount) {
inBuf += amount;
if ((bufpos -= amount) < 0)
- bufpos += bufsize;
+ bufpos += bufsize;
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
@@ -267,16 +281,20 @@ public class SimpleCharStream
bufcolumn = new int[buffersize];
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn)
{
- this(dstream, startline, startcolumn, 4096);
+ this(dstream, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream)
{
- this(dstream, 1, 1, 4096);
+ this(dstream, 1, 1, 4096);
}
+
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
@@ -296,111 +314,128 @@ public class SimpleCharStream
bufpos = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn)
{
- ReInit(dstream, startline, startcolumn, 4096);
+ ReInit(dstream, startline, startcolumn, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream)
{
- ReInit(dstream, 1, 1, 4096);
+ ReInit(dstream, 1, 1, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
- this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
- this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
- this(dstream, encoding, startline, startcolumn, 4096);
+ this(dstream, encoding, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn)
{
- this(dstream, startline, startcolumn, 4096);
+ this(dstream, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
- this(dstream, encoding, 1, 1, 4096);
+ this(dstream, encoding, 1, 1, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream)
{
- this(dstream, 1, 1, 4096);
+ this(dstream, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
- ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
- ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
- ReInit(dstream, encoding, 1, 1, 4096);
+ ReInit(dstream, encoding, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream)
{
- ReInit(dstream, 1, 1, 4096);
+ ReInit(dstream, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
- ReInit(dstream, encoding, startline, startcolumn, 4096);
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn)
{
- ReInit(dstream, startline, startcolumn, 4096);
+ ReInit(dstream, startline, startcolumn, 4096);
}
+ /** Get token literal value. */
public String GetImage()
{
- if (bufpos >= tokenBegin)
- return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
- else
- return new String(buffer, tokenBegin, bufsize - tokenBegin) +
- new String(buffer, 0, bufpos + 1);
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
}
+ /** Get the suffix. */
public char[] GetSuffix(int len)
{
- char[] ret = new char[len];
+ char[] ret = new char[len];
- if ((bufpos + 1) >= len)
- System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
- else
- {
- System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
- len - bufpos - 1);
- System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
- }
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
- return ret;
+ return ret;
}
+ /** Reset buffer when finished. */
public void Done()
{
- buffer = null;
- bufline = null;
- bufcolumn = null;
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
}
/**
@@ -408,47 +443,47 @@ public class SimpleCharStream
*/
public void adjustBeginLineColumn(int newLine, int newCol)
{
- int start = tokenBegin;
- int len;
+ int start = tokenBegin;
+ int len;
- if (bufpos >= tokenBegin)
- {
- len = bufpos - tokenBegin + inBuf + 1;
- }
- else
- {
- len = bufsize - tokenBegin + bufpos + 1 + inBuf;
- }
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
- int i = 0, j = 0, k = 0;
- int nextColDiff = 0, columnDiff = 0;
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
- while (i < len &&
- bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
- {
- bufline[j] = newLine;
- nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
- bufcolumn[j] = newCol + columnDiff;
- columnDiff = nextColDiff;
- i++;
- }
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
- if (i < len)
- {
- bufline[j] = newLine++;
- bufcolumn[j] = newCol + columnDiff;
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
- while (i++ < len)
- {
- if (bufline[j = start % bufsize] != bufline[++start % bufsize])
- bufline[j] = newLine++;
- else
- bufline[j] = newLine;
- }
- }
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
- line = bufline[j];
- column = bufcolumn[j];
+ line = bufline[j];
+ column = bufcolumn[j];
}
}
+/* JavaCC - OriginalChecksum=6c6aad23fd4c0ff4139b17758b7e8610 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/Token.java b/src/org/apache/james/mime4j/field/contenttype/parser/Token.java
index 5bef6cf02..aa509517f 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/Token.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/Token.java
@@ -1,26 +1,37 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.contenttype.parser;
/**
* Describes the input token stream.
*/
-public class Token {
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
/**
* An integer that describes the kind of this token. This numbering
@@ -29,12 +40,14 @@ public class Token {
*/
public int kind;
- /**
- * beginLine and beginColumn describe the position of the first character
- * of this token; endLine and endColumn describe the position of the
- * last character of this token.
- */
- public int beginLine, beginColumn, endLine, endColumn;
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
/**
* The string image of the token.
@@ -65,12 +78,46 @@ public class Token {
*/
public Token specialToken;
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
/**
* Returns the image.
*/
public String toString()
{
- return image;
+ return image;
}
/**
@@ -78,19 +125,25 @@ public class Token {
* can create and return subclass objects based on the value of ofKind.
* Simply add the cases to the switch for all those special cases.
* For example, if you have a subclass of Token called IDToken that
- * you want to create if ofKind is ID, simlpy add something like :
+ * you want to create if ofKind is ID, simply add something like :
*
- * case MyParserConstants.ID : return new IDToken();
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
*
* to the following switch statement. Then you can cast matchedToken
- * variable to the appropriate type and use it in your lexical actions.
+ * variable to the appropriate type and use sit in your lexical actions.
*/
- public static final Token newToken(int ofKind)
+ public static Token newToken(int ofKind, String image)
{
- switch(ofKind)
- {
- default : return new Token();
- }
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
}
}
+/* JavaCC - OriginalChecksum=3d41123d7d22080e3366761725b1c1fe (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java
index 4a490efac..5849559d1 100644
--- a/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java
+++ b/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java
@@ -1,148 +1,165 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+/****************************************************************
+ * 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.contenttype.parser;
+/** Token Manager Error. */
public class TokenMgrError extends Error
{
- /*
- * Ordinals for various reasons why an Error of this type can be thrown.
- */
- /**
- * Lexical error occured.
- */
- static final int LEXICAL_ERROR = 0;
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
- /**
- * An attempt wass made to create a second instance of a static token manager.
- */
- static final int STATIC_LEXER_ERROR = 1;
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
- /**
- * Tried to change to an invalid lexical state.
- */
- static final int INVALID_LEXICAL_STATE = 2;
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
- /**
- * Detected (and bailed out of) an infinite loop in the token manager.
- */
- static final int LOOP_DETECTED = 3;
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
- /**
- * Indicates the reason why the exception is thrown. It will have
- * one of the above 4 values.
- */
- int errorCode;
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
- /**
- * Replaces unprintable characters by their espaced (or unicode escaped)
- * equivalents in the given string
- */
- protected static final String addEscapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
}
- return retval.toString();
- }
+ }
+ return retval.toString();
+ }
- /**
- * Returns a detailed message for the Error when it is thrown by the
- * token manager to indicate a lexical error.
- * Parameters :
- * EOFSeen : indicates if EOF caused the lexicl error
- * curLexState : lexical state in which this error occured
- * errorLine : line number when the error occured
- * errorColumn : column number when the error occured
- * errorAfter : prefix that was seen before this error occured
- * curchar : the offending character
- * Note: You can customize the lexical error message by modifying this method.
- */
- protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
- return("Lexical error at line " +
- errorLine + ", column " +
- errorColumn + ". Encountered: " +
- (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
- "after : \"" + addEscapes(errorAfter) + "\"");
- }
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
- /**
- * You can also modify the body of this method to customize your error messages.
- * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
- * of end-users concern, so you can return something like :
- *
- * "Internal Error : Please file a bug report .... "
- *
- * from this method for such cases in the release version of your parser.
- */
- public String getMessage() {
- return super.getMessage();
- }
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
- /*
- * Constructors of various flavors follow.
- */
+ /*
+ * Constructors of various flavors follow.
+ */
- public TokenMgrError() {
- }
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
- public TokenMgrError(String message, int reason) {
- super(message);
- errorCode = reason;
- }
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
- public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
- this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
- }
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
}
+/* JavaCC - OriginalChecksum=75c4cf7db7d0ac3344c6bae5c180f189 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java
index 94b517208..a9af27ac5 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java
@@ -1,24 +1,25 @@
/* Generated By:JavaCC: Do not edit this line. DateTimeParser.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.datetime.parser;
-import org.apache.james.mime4j.field.datetime.DateTime;
-
-import java.util.Calendar;
+import org.apache.james.mime4j.dom.datetime.DateTime;
public class DateTimeParser implements DateTimeParserConstants {
private static final boolean ignoreMilitaryZoneOffset = true;
@@ -406,28 +407,34 @@ public class DateTimeParser implements DateTimeParserConstants {
throw new Error("Missing return statement in function");
}
+ /** Generated Token Manager. */
public DateTimeParserTokenManager token_source;
SimpleCharStream jj_input_stream;
- public Token token, jj_nt;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
private int jj_ntk;
private int jj_gen;
final private int[] jj_la1 = new int[7];
static private int[] jj_la1_0;
static private int[] jj_la1_1;
static {
- jj_la1_0();
- jj_la1_1();
+ jj_la1_init_0();
+ jj_la1_init_1();
}
- private static void jj_la1_0() {
+ private static void jj_la1_init_0() {
jj_la1_0 = new int[] {0x2,0x7f0,0x7f0,0x7ff800,0x800000,0xff000000,0xfe000000,};
}
- private static void jj_la1_1() {
+ private static void jj_la1_init_1() {
jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0xf,0xf,};
}
+ /** Constructor with InputStream. */
public DateTimeParser(java.io.InputStream stream) {
this(stream, null);
}
+ /** Constructor with InputStream and supplied encoding */
public DateTimeParser(java.io.InputStream stream, String encoding) {
try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
token_source = new DateTimeParserTokenManager(jj_input_stream);
@@ -437,9 +444,11 @@ public class DateTimeParser implements DateTimeParserConstants {
for (int i = 0; i < 7; i++) jj_la1[i] = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream stream) {
ReInit(stream, null);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream stream, String encoding) {
try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
token_source.ReInit(jj_input_stream);
@@ -449,6 +458,7 @@ public class DateTimeParser implements DateTimeParserConstants {
for (int i = 0; i < 7; i++) jj_la1[i] = -1;
}
+ /** Constructor. */
public DateTimeParser(java.io.Reader stream) {
jj_input_stream = new SimpleCharStream(stream, 1, 1);
token_source = new DateTimeParserTokenManager(jj_input_stream);
@@ -458,6 +468,7 @@ public class DateTimeParser implements DateTimeParserConstants {
for (int i = 0; i < 7; i++) jj_la1[i] = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader stream) {
jj_input_stream.ReInit(stream, 1, 1);
token_source.ReInit(jj_input_stream);
@@ -467,6 +478,7 @@ public class DateTimeParser implements DateTimeParserConstants {
for (int i = 0; i < 7; i++) jj_la1[i] = -1;
}
+ /** Constructor with generated Token Manager. */
public DateTimeParser(DateTimeParserTokenManager tm) {
token_source = tm;
token = new Token();
@@ -475,6 +487,7 @@ public class DateTimeParser implements DateTimeParserConstants {
for (int i = 0; i < 7; i++) jj_la1[i] = -1;
}
+ /** Reinitialise. */
public void ReInit(DateTimeParserTokenManager tm) {
token_source = tm;
token = new Token();
@@ -483,7 +496,7 @@ public class DateTimeParser implements DateTimeParserConstants {
for (int i = 0; i < 7; i++) jj_la1[i] = -1;
}
- final private Token jj_consume_token(int kind) throws ParseException {
+ private Token jj_consume_token(int kind) throws ParseException {
Token oldToken;
if ((oldToken = token).next != null) token = token.next;
else token = token.next = token_source.getNextToken();
@@ -497,6 +510,8 @@ public class DateTimeParser implements DateTimeParserConstants {
throw generateParseException();
}
+
+/** Get the next Token. */
final public Token getNextToken() {
if (token.next != null) token = token.next;
else token = token.next = token_source.getNextToken();
@@ -505,6 +520,7 @@ public class DateTimeParser implements DateTimeParserConstants {
return token;
}
+/** Get the specific Token. */
final public Token getToken(int index) {
Token t = token;
for (int i = 0; i < index; i++) {
@@ -514,23 +530,21 @@ public class DateTimeParser implements DateTimeParserConstants {
return t;
}
- final private int jj_ntk() {
+ private int jj_ntk() {
if ((jj_nt=token.next) == null)
return (jj_ntk = (token.next=token_source.getNextToken()).kind);
else
return (jj_ntk = jj_nt.kind);
}
- private java.util.Vector jj_expentries = new java.util.Vector();
+ private java.util.List jj_expentries = new java.util.ArrayList();
private int[] jj_expentry;
private int jj_kind = -1;
+ /** Generate ParseException. */
public ParseException generateParseException() {
- jj_expentries.removeAllElements();
+ jj_expentries.clear();
boolean[] la1tokens = new boolean[49];
- for (int i = 0; i < 49; i++) {
- la1tokens[i] = false;
- }
if (jj_kind >= 0) {
la1tokens[jj_kind] = true;
jj_kind = -1;
@@ -551,19 +565,21 @@ public class DateTimeParser implements DateTimeParserConstants {
if (la1tokens[i]) {
jj_expentry = new int[1];
jj_expentry[0] = i;
- jj_expentries.addElement(jj_expentry);
+ jj_expentries.add(jj_expentry);
}
}
int[][] exptokseq = new int[jj_expentries.size()][];
for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = (int[])jj_expentries.elementAt(i);
+ exptokseq[i] = jj_expentries.get(i);
}
return new ParseException(token, exptokseq, tokenImage);
}
+ /** Enable tracing. */
final public void enable_tracing() {
}
+ /** Disable tracing. */
final public void disable_tracing() {
}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java
index 17389d816..638f5bbbd 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java
@@ -1,36 +1,56 @@
/* Generated By:JavaCC: Do not edit this line. DateTimeParserConstants.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.datetime.parser;
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
public interface DateTimeParserConstants {
+ /** End of File. */
int EOF = 0;
+ /** RegularExpression Id. */
int OFFSETDIR = 24;
+ /** RegularExpression Id. */
int MILITARY_ZONE = 35;
+ /** RegularExpression Id. */
int WS = 36;
+ /** RegularExpression Id. */
int COMMENT = 38;
+ /** RegularExpression Id. */
int DIGITS = 46;
+ /** RegularExpression Id. */
int QUOTEDPAIR = 47;
+ /** RegularExpression Id. */
int ANY = 48;
+ /** Lexical state. */
int DEFAULT = 0;
+ /** Lexical state. */
int INCOMMENT = 1;
+ /** Lexical state. */
int NESTED_COMMENT = 2;
+ /** Literal token values. */
String[] tokenImage = {
"",
"\"\\r\"",
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java
index e75998cf2..858b0509d 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java
@@ -1,23 +1,26 @@
/* Generated By:JavaCC: Do not edit this line. DateTimeParserTokenManager.java */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.datetime.parser;
-import org.apache.james.mime4j.field.datetime.DateTime;
-import java.util.Calendar;
+import org.apache.james.mime4j.dom.datetime.DateTime;
+/** Token Manager. */
public class DateTimeParserTokenManager implements DateTimeParserConstants
{
// Keeps track of how many levels of comment nesting
@@ -27,7 +30,10 @@ public class DateTimeParserTokenManager implements DateTimeParserConstants
// specially anyway, because the outermost ")" has a
// different token type than inner ")" instances.
static int commentNest;
+
+ /** Debug output. */
public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
private final int jjStopStringLiteralDfa_0(int pos, long active0)
{
@@ -59,21 +65,13 @@ private final int jjStartNfa_0(int pos, long active0)
{
return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
}
-private final int jjStopAtPos(int pos, int kind)
+private int jjStopAtPos(int pos, int kind)
{
jjmatchedKind = kind;
jjmatchedPos = pos;
return pos + 1;
}
-private final int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_0(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_0()
+private int jjMoveStringLiteralDfa0_0()
{
switch(curChar)
{
@@ -121,7 +119,7 @@ private final int jjMoveStringLiteralDfa0_0()
return jjMoveNfa_0(0, 0);
}
}
-private final int jjMoveStringLiteralDfa1_0(long active0)
+private int jjMoveStringLiteralDfa1_0(long active0)
{
try { curChar = input_stream.readChar(); }
catch(java.io.IOException e) {
@@ -161,10 +159,10 @@ private final int jjMoveStringLiteralDfa1_0(long active0)
}
return jjStartNfa_0(0, active0);
}
-private final int jjMoveStringLiteralDfa2_0(long old0, long active0)
+private int jjMoveStringLiteralDfa2_0(long old0, long active0)
{
if (((active0 &= old0)) == 0L)
- return jjStartNfa_0(0, old0);
+ return jjStartNfa_0(0, old0);
try { curChar = input_stream.readChar(); }
catch(java.io.IOException e) {
jjStopStringLiteralDfa_0(1, active0);
@@ -263,44 +261,13 @@ private final int jjMoveStringLiteralDfa2_0(long old0, long active0)
}
return jjStartNfa_0(1, active0);
}
-private final void jjCheckNAdd(int state)
+private int jjMoveNfa_0(int startState, int curPos)
{
- if (jjrounds[state] != jjround)
- {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
- }
-}
-private final void jjAddStates(int start, int end)
-{
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
-}
-private final void jjCheckNAddTwoStates(int state1, int state2)
-{
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
-}
-private final void jjCheckNAddStates(int start, int end)
-{
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
-}
-private final void jjCheckNAddStates(int start)
-{
- jjCheckNAdd(jjnextStates[start]);
- jjCheckNAdd(jjnextStates[start + 1]);
-}
-private final int jjMoveNfa_0(int startState, int curPos)
-{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 4;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -308,7 +275,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -350,7 +317,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -366,7 +333,7 @@ private final int jjMoveNfa_0(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -399,15 +366,7 @@ private final int jjStartNfa_1(int pos, long active0)
{
return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_1(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_1(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_1()
+private int jjMoveStringLiteralDfa0_1()
{
switch(curChar)
{
@@ -422,14 +381,13 @@ private final int jjMoveStringLiteralDfa0_1()
static final long[] jjbitVec0 = {
0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
};
-private final int jjMoveNfa_1(int startState, int curPos)
+private int jjMoveNfa_1(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -437,7 +395,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -456,7 +414,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -482,7 +440,7 @@ private final int jjMoveNfa_1(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -523,15 +481,7 @@ private final int jjStartNfa_2(int pos, long active0)
{
return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
}
-private final int jjStartNfaWithStates_2(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_2(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_2()
+private int jjMoveStringLiteralDfa0_2()
{
switch(curChar)
{
@@ -543,14 +493,13 @@ private final int jjMoveStringLiteralDfa0_2()
return jjMoveNfa_2(0, 0);
}
}
-private final int jjMoveNfa_2(int startState, int curPos)
+private int jjMoveNfa_2(int startState, int curPos)
{
- int[] nextStates;
int startsAt = 0;
jjnewStateCnt = 3;
int i = 1;
jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
+ int kind = 0x7fffffff;
for (;;)
{
if (++jjround == 0x7fffffff)
@@ -558,7 +507,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
if (curChar < 64)
{
long l = 1L << curChar;
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -577,7 +526,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
else if (curChar < 128)
{
long l = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -603,7 +552,7 @@ private final int jjMoveNfa_2(int startState, int curPos)
{
int i2 = (curChar & 0xff) >> 6;
long l2 = 1L << (curChar & 077);
- MatchLoop: do
+ do
{
switch(jjstateSet[--i])
{
@@ -634,6 +583,8 @@ private final int jjMoveNfa_2(int startState, int curPos)
}
static final int[] jjnextStates = {
};
+
+/** Token literal values. */
public static final String[] jjstrLiteralImages = {
"", "\15", "\12", "\54", "\115\157\156", "\124\165\145", "\127\145\144",
"\124\150\165", "\106\162\151", "\123\141\164", "\123\165\156", "\112\141\156",
@@ -643,11 +594,15 @@ public static final String[] jjstrLiteralImages = {
"\103\123\124", "\103\104\124", "\115\123\124", "\115\104\124", "\120\123\124",
"\120\104\124", null, null, null, null, null, null, null, null, null, null, null, null, null,
null, };
+
+/** Lexer state names. */
public static final String[] lexStateNames = {
- "DEFAULT",
- "INCOMMENT",
- "NESTED_COMMENT",
+ "DEFAULT",
+ "INCOMMENT",
+ "NESTED_COMMENT",
};
+
+/** Lex State array. */
public static final int[] jjnewLexState = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -667,19 +622,25 @@ static final long[] jjtoMore = {
protected SimpleCharStream input_stream;
private final int[] jjrounds = new int[4];
private final int[] jjstateSet = new int[8];
-StringBuffer image;
-int jjimageLen;
-int lengthOfMatch;
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
protected char curChar;
+/** Constructor. */
public DateTimeParserTokenManager(SimpleCharStream stream){
if (SimpleCharStream.staticFlag)
throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
input_stream = stream;
}
+
+/** Constructor. */
public DateTimeParserTokenManager(SimpleCharStream stream, int lexState){
this(stream);
SwitchTo(lexState);
}
+
+/** Reinitialise parser. */
public void ReInit(SimpleCharStream stream)
{
jjmatchedPos = jjnewStateCnt = 0;
@@ -687,18 +648,22 @@ public void ReInit(SimpleCharStream stream)
input_stream = stream;
ReInitRounds();
}
-private final void ReInitRounds()
+private void ReInitRounds()
{
int i;
jjround = 0x80000001;
for (i = 4; i-- > 0;)
jjrounds[i] = 0x80000000;
}
+
+/** Reinitialise parser. */
public void ReInit(SimpleCharStream stream, int lexState)
{
ReInit(stream);
SwitchTo(lexState);
}
+
+/** Switch to specified lex state. */
public void SwitchTo(int lexState)
{
if (lexState >= 3 || lexState < 0)
@@ -709,14 +674,25 @@ public void SwitchTo(int lexState)
protected Token jjFillToken()
{
- Token t = Token.newToken(jjmatchedKind);
- t.kind = jjmatchedKind;
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
String im = jjstrLiteralImages[jjmatchedKind];
- t.image = (im == null) ? input_stream.GetImage() : im;
- t.beginLine = input_stream.getBeginLine();
- t.beginColumn = input_stream.getBeginColumn();
- t.endLine = input_stream.getEndLine();
- t.endColumn = input_stream.getEndColumn();
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
return t;
}
@@ -727,28 +703,29 @@ int jjround;
int jjmatchedPos;
int jjmatchedKind;
+/** Get the next Token. */
public Token getNextToken()
{
- int kind;
Token specialToken = null;
Token matchedToken;
int curPos = 0;
EOFLoop :
for (;;)
- {
- try
- {
+ {
+ try
+ {
curChar = input_stream.BeginToken();
- }
+ }
catch(java.io.IOException e)
- {
+ {
jjmatchedKind = 0;
matchedToken = jjFillToken();
matchedToken.specialToken = specialToken;
return matchedToken;
}
- image = null;
+ image = jjimage;
+ image.setLength(0);
jjimageLen = 0;
for (;;)
@@ -841,42 +818,52 @@ void MoreLexicalActions()
switch(jjmatchedKind)
{
case 39 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 40 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
commentNest = 1;
break;
case 42 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
image.deleteCharAt(image.length() - 2);
break;
case 43 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
++commentNest;
break;
case 44 :
- if (image == null)
- image = new StringBuffer();
image.append(input_stream.GetSuffix(jjimageLen));
jjimageLen = 0;
--commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
break;
- default :
+ default :
break;
}
}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java b/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java
index 418699107..ee78a79a3 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java
@@ -1,19 +1,22 @@
/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/****************************************************************
+ * 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.datetime.parser;
/**
@@ -22,10 +25,15 @@ package org.apache.james.mime4j.field.datetime.parser;
* calling the method generateParseException in the generated
* parser.
*
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
*/
-public class ParseException extends Exception {
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
/**
* This constructor is used by the method "generateParseException"
@@ -62,7 +70,12 @@ public class ParseException extends Exception {
*/
public ParseException() {
- super();
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
specialConstructor = false;
}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java
index d44a9018b..0455cf1ec 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java
@@ -1,19 +1,23 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.datetime.parser;
/**
@@ -23,10 +27,12 @@ package org.apache.james.mime4j.field.datetime.parser;
public class SimpleCharStream
{
+/** Whether parser is static. */
public static final boolean staticFlag = false;
int bufsize;
int available;
int tokenBegin;
+/** Position in buffer. */
public int bufpos = -1;
protected int bufline[];
protected int bufcolumn[];
@@ -50,210 +56,218 @@ public class SimpleCharStream
protected void ExpandBuff(boolean wrapAround)
{
- char[] newbuffer = new char[bufsize + 2048];
- int newbufline[] = new int[bufsize + 2048];
- int newbufcolumn[] = new int[bufsize + 2048];
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
- try
- {
- if (wrapAround)
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- System.arraycopy(buffer, 0, newbuffer,
- bufsize - tokenBegin, bufpos);
- buffer = newbuffer;
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
- bufline = newbufline;
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
- bufcolumn = newbufcolumn;
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
- maxNextCharInd = (bufpos += (bufsize - tokenBegin));
- }
- else
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- buffer = newbuffer;
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- bufline = newbufline;
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- bufcolumn = newbufcolumn;
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
- maxNextCharInd = (bufpos -= tokenBegin);
- }
- }
- catch (Throwable t)
- {
- throw new Error(t.getMessage());
- }
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
- bufsize += 2048;
- available = bufsize;
- tokenBegin = 0;
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
}
protected void FillBuff() throws java.io.IOException
{
- if (maxNextCharInd == available)
- {
- if (available == bufsize)
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
{
- if (tokenBegin > 2048)
- {
- bufpos = maxNextCharInd = 0;
- available = tokenBegin;
- }
- else if (tokenBegin < 0)
- bufpos = maxNextCharInd = 0;
- else
- ExpandBuff(false);
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
}
- else if (available > tokenBegin)
- available = bufsize;
- else if ((tokenBegin - available) < 2048)
- ExpandBuff(true);
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
else
- available = tokenBegin;
- }
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
- int i;
- try {
- if ((i = inputStream.read(buffer, maxNextCharInd,
- available - maxNextCharInd)) == -1)
- {
- inputStream.close();
- throw new java.io.IOException();
- }
- else
- maxNextCharInd += i;
- return;
- }
- catch(java.io.IOException e) {
- --bufpos;
- backup(0);
- if (tokenBegin == -1)
- tokenBegin = bufpos;
- throw e;
- }
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
}
+/** Start. */
public char BeginToken() throws java.io.IOException
{
- tokenBegin = -1;
- char c = readChar();
- tokenBegin = bufpos;
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
- return c;
+ return c;
}
protected void UpdateLineColumn(char c)
{
- column++;
+ column++;
- if (prevCharIsLF)
- {
- prevCharIsLF = false;
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
line += (column = 1);
- }
- else if (prevCharIsCR)
- {
- prevCharIsCR = false;
- if (c == '\n')
- {
- prevCharIsLF = true;
- }
- else
- line += (column = 1);
- }
+ }
- switch (c)
- {
- case '\r' :
- prevCharIsCR = true;
- break;
- case '\n' :
- prevCharIsLF = true;
- break;
- case '\t' :
- column--;
- column += (tabSize - (column % tabSize));
- break;
- default :
- break;
- }
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
- bufline[bufpos] = line;
- bufcolumn[bufpos] = column;
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
}
+/** Read a character. */
public char readChar() throws java.io.IOException
{
- if (inBuf > 0)
- {
- --inBuf;
+ if (inBuf > 0)
+ {
+ --inBuf;
- if (++bufpos == bufsize)
- bufpos = 0;
+ if (++bufpos == bufsize)
+ bufpos = 0;
- return buffer[bufpos];
- }
+ return buffer[bufpos];
+ }
- if (++bufpos >= maxNextCharInd)
- FillBuff();
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
- char c = buffer[bufpos];
+ char c = buffer[bufpos];
- UpdateLineColumn(c);
- return (c);
+ UpdateLineColumn(c);
+ return c;
}
+ @Deprecated
/**
- * @deprecated
+ * @deprecated
* @see #getEndColumn
*/
public int getColumn() {
- return bufcolumn[bufpos];
+ return bufcolumn[bufpos];
}
+ @Deprecated
/**
- * @deprecated
+ * @deprecated
* @see #getEndLine
*/
public int getLine() {
- return bufline[bufpos];
+ return bufline[bufpos];
}
+ /** Get token end column number. */
public int getEndColumn() {
- return bufcolumn[bufpos];
+ return bufcolumn[bufpos];
}
+ /** Get token end line number. */
public int getEndLine() {
return bufline[bufpos];
}
+ /** Get token beginning column number. */
public int getBeginColumn() {
- return bufcolumn[tokenBegin];
+ return bufcolumn[tokenBegin];
}
+ /** Get token beginning line number. */
public int getBeginLine() {
- return bufline[tokenBegin];
+ return bufline[tokenBegin];
}
+/** Backup a number of characters. */
public void backup(int amount) {
inBuf += amount;
if ((bufpos -= amount) < 0)
- bufpos += bufsize;
+ bufpos += bufsize;
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
@@ -267,16 +281,20 @@ public class SimpleCharStream
bufcolumn = new int[buffersize];
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream, int startline,
int startcolumn)
{
- this(dstream, startline, startcolumn, 4096);
+ this(dstream, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.Reader dstream)
{
- this(dstream, 1, 1, 4096);
+ this(dstream, 1, 1, 4096);
}
+
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn, int buffersize)
{
@@ -296,111 +314,128 @@ public class SimpleCharStream
bufpos = -1;
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream, int startline,
int startcolumn)
{
- ReInit(dstream, startline, startcolumn, 4096);
+ ReInit(dstream, startline, startcolumn, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.Reader dstream)
{
- ReInit(dstream, 1, 1, 4096);
+ ReInit(dstream, 1, 1, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
- this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
- this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
- this(dstream, encoding, startline, startcolumn, 4096);
+ this(dstream, encoding, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, int startline,
int startcolumn)
{
- this(dstream, startline, startcolumn, 4096);
+ this(dstream, startline, startcolumn, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
- this(dstream, encoding, 1, 1, 4096);
+ this(dstream, encoding, 1, 1, 4096);
}
+ /** Constructor. */
public SimpleCharStream(java.io.InputStream dstream)
{
- this(dstream, 1, 1, 4096);
+ this(dstream, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
{
- ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn, int buffersize)
{
- ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
{
- ReInit(dstream, encoding, 1, 1, 4096);
+ ReInit(dstream, encoding, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream)
{
- ReInit(dstream, 1, 1, 4096);
+ ReInit(dstream, 1, 1, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, String encoding, int startline,
int startcolumn) throws java.io.UnsupportedEncodingException
{
- ReInit(dstream, encoding, startline, startcolumn, 4096);
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
}
+ /** Reinitialise. */
public void ReInit(java.io.InputStream dstream, int startline,
int startcolumn)
{
- ReInit(dstream, startline, startcolumn, 4096);
+ ReInit(dstream, startline, startcolumn, 4096);
}
+ /** Get token literal value. */
public String GetImage()
{
- if (bufpos >= tokenBegin)
- return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
- else
- return new String(buffer, tokenBegin, bufsize - tokenBegin) +
- new String(buffer, 0, bufpos + 1);
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
}
+ /** Get the suffix. */
public char[] GetSuffix(int len)
{
- char[] ret = new char[len];
+ char[] ret = new char[len];
- if ((bufpos + 1) >= len)
- System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
- else
- {
- System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
- len - bufpos - 1);
- System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
- }
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
- return ret;
+ return ret;
}
+ /** Reset buffer when finished. */
public void Done()
{
- buffer = null;
- bufline = null;
- bufcolumn = null;
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
}
/**
@@ -408,47 +443,47 @@ public class SimpleCharStream
*/
public void adjustBeginLineColumn(int newLine, int newCol)
{
- int start = tokenBegin;
- int len;
+ int start = tokenBegin;
+ int len;
- if (bufpos >= tokenBegin)
- {
- len = bufpos - tokenBegin + inBuf + 1;
- }
- else
- {
- len = bufsize - tokenBegin + bufpos + 1 + inBuf;
- }
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
- int i = 0, j = 0, k = 0;
- int nextColDiff = 0, columnDiff = 0;
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
- while (i < len &&
- bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
- {
- bufline[j] = newLine;
- nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
- bufcolumn[j] = newCol + columnDiff;
- columnDiff = nextColDiff;
- i++;
- }
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
- if (i < len)
- {
- bufline[j] = newLine++;
- bufcolumn[j] = newCol + columnDiff;
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
- while (i++ < len)
- {
- if (bufline[j = start % bufsize] != bufline[++start % bufsize])
- bufline[j] = newLine++;
- else
- bufline[j] = newLine;
- }
- }
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
- line = bufline[j];
- column = bufcolumn[j];
+ line = bufline[j];
+ column = bufcolumn[j];
}
}
+/* JavaCC - OriginalChecksum=48cd9bc600ae4a033ab56787d790871f (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/Token.java b/src/org/apache/james/mime4j/field/datetime/parser/Token.java
index 52d101ed0..986b62b89 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/Token.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/Token.java
@@ -1,26 +1,37 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.datetime.parser;
/**
* Describes the input token stream.
*/
-public class Token {
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
/**
* An integer that describes the kind of this token. This numbering
@@ -29,12 +40,14 @@ public class Token {
*/
public int kind;
- /**
- * beginLine and beginColumn describe the position of the first character
- * of this token; endLine and endColumn describe the position of the
- * last character of this token.
- */
- public int beginLine, beginColumn, endLine, endColumn;
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
/**
* The string image of the token.
@@ -65,12 +78,46 @@ public class Token {
*/
public Token specialToken;
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
/**
* Returns the image.
*/
public String toString()
{
- return image;
+ return image;
}
/**
@@ -78,19 +125,25 @@ public class Token {
* can create and return subclass objects based on the value of ofKind.
* Simply add the cases to the switch for all those special cases.
* For example, if you have a subclass of Token called IDToken that
- * you want to create if ofKind is ID, simlpy add something like :
+ * you want to create if ofKind is ID, simply add something like :
*
- * case MyParserConstants.ID : return new IDToken();
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
*
* to the following switch statement. Then you can cast matchedToken
- * variable to the appropriate type and use it in your lexical actions.
+ * variable to the appropriate type and use sit in your lexical actions.
*/
- public static final Token newToken(int ofKind)
+ public static Token newToken(int ofKind, String image)
{
- switch(ofKind)
- {
- default : return new Token();
- }
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
}
}
+/* JavaCC - OriginalChecksum=33f05393bf2567608f7c35f8b9169767 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java
index 973255070..14fcc43a8 100644
--- a/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java
+++ b/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java
@@ -1,148 +1,165 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j project
- *
- * Licensed 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.
- */
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+/****************************************************************
+ * 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.datetime.parser;
+/** Token Manager Error. */
public class TokenMgrError extends Error
{
- /*
- * Ordinals for various reasons why an Error of this type can be thrown.
- */
- /**
- * Lexical error occured.
- */
- static final int LEXICAL_ERROR = 0;
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
- /**
- * An attempt wass made to create a second instance of a static token manager.
- */
- static final int STATIC_LEXER_ERROR = 1;
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
- /**
- * Tried to change to an invalid lexical state.
- */
- static final int INVALID_LEXICAL_STATE = 2;
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
- /**
- * Detected (and bailed out of) an infinite loop in the token manager.
- */
- static final int LOOP_DETECTED = 3;
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
- /**
- * Indicates the reason why the exception is thrown. It will have
- * one of the above 4 values.
- */
- int errorCode;
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
- /**
- * Replaces unprintable characters by their espaced (or unicode escaped)
- * equivalents in the given string
- */
- protected static final String addEscapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
}
- return retval.toString();
- }
+ }
+ return retval.toString();
+ }
- /**
- * Returns a detailed message for the Error when it is thrown by the
- * token manager to indicate a lexical error.
- * Parameters :
- * EOFSeen : indicates if EOF caused the lexicl error
- * curLexState : lexical state in which this error occured
- * errorLine : line number when the error occured
- * errorColumn : column number when the error occured
- * errorAfter : prefix that was seen before this error occured
- * curchar : the offending character
- * Note: You can customize the lexical error message by modifying this method.
- */
- protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
- return("Lexical error at line " +
- errorLine + ", column " +
- errorColumn + ". Encountered: " +
- (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
- "after : \"" + addEscapes(errorAfter) + "\"");
- }
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
- /**
- * You can also modify the body of this method to customize your error messages.
- * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
- * of end-users concern, so you can return something like :
- *
- * "Internal Error : Please file a bug report .... "
- *
- * from this method for such cases in the release version of your parser.
- */
- public String getMessage() {
- return super.getMessage();
- }
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
- /*
- * Constructors of various flavors follow.
- */
+ /*
+ * Constructors of various flavors follow.
+ */
- public TokenMgrError() {
- }
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
- public TokenMgrError(String message, int reason) {
- super(message);
- errorCode = reason;
- }
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
- public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
- this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
- }
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
}
+/* JavaCC - OriginalChecksum=375b294dc4b23ad797e2b1145d1bfa1e (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/language/parser/ContentLanguageParser.java b/src/org/apache/james/mime4j/field/language/parser/ContentLanguageParser.java
new file mode 100644
index 000000000..643cf159c
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/language/parser/ContentLanguageParser.java
@@ -0,0 +1,272 @@
+/* Generated By:JavaCC: Do not edit this line. ContentLanguageParser.java */
+/****************************************************************
+ * 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.language.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContentLanguageParser implements ContentLanguageParserConstants {
+ private List languages = new ArrayList();
+
+ /**
+ * Parses the input into a list of language tags.
+ * @return list of language tag Strings
+ */
+ public List parse() throws ParseException {
+ try {
+ return doParse();
+ } catch (TokenMgrError e) {
+ // An issue with the TOKENiser
+ // but it's not polite to throw an Error
+ // when executing on a server
+ throw new ParseException(e);
+ }
+ }
+
+ final private List doParse() throws ParseException {
+ language();
+ label_1:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case 1:
+ ;
+ break;
+ default:
+ jj_la1[0] = jj_gen;
+ break label_1;
+ }
+ jj_consume_token(1);
+ language();
+ }
+ {if (true) return languages;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public String language() throws ParseException {
+ Token token;
+ StringBuffer languageTag = new StringBuffer();
+ String result;
+ token = jj_consume_token(ALPHA);
+ languageTag.append(token.image);
+ label_2:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case 2:
+ case ALPHANUM:
+ ;
+ break;
+ default:
+ jj_la1[1] = jj_gen;
+ break label_2;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case 2:
+ jj_consume_token(2);
+ // This keeps TOKENising simple
+ token = jj_consume_token(ALPHA);
+ languageTag.append('-');
+ languageTag.append(token.image);
+ break;
+ case ALPHANUM:
+ token = jj_consume_token(ALPHANUM);
+ languageTag.append('-');
+ languageTag.append(token.image);
+ break;
+ default:
+ jj_la1[2] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ result = languageTag.toString();
+ languages.add(result);
+ {if (true) return result;}
+ throw new Error("Missing return statement in function");
+ }
+
+ /** Generated Token Manager. */
+ public ContentLanguageParserTokenManager token_source;
+ SimpleCharStream jj_input_stream;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
+ private int jj_ntk;
+ private int jj_gen;
+ final private int[] jj_la1 = new int[3];
+ static private int[] jj_la1_0;
+ static {
+ jj_la1_init_0();
+ }
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0x2,0x80004,0x80004,};
+ }
+
+ /** Constructor with InputStream. */
+ public ContentLanguageParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+ /** Constructor with InputStream and supplied encoding */
+ public ContentLanguageParser(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source = new ContentLanguageParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream) {
+ ReInit(stream, null);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor. */
+ public ContentLanguageParser(java.io.Reader stream) {
+ jj_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new ContentLanguageParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader stream) {
+ jj_input_stream.ReInit(stream, 1, 1);
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor with generated Token Manager. */
+ public ContentLanguageParser(ContentLanguageParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(ContentLanguageParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 3; i++) jj_la1[i] = -1;
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ if (token.kind == kind) {
+ jj_gen++;
+ return token;
+ }
+ token = oldToken;
+ jj_kind = kind;
+ throw generateParseException();
+ }
+
+
+/** Get the next Token. */
+ final public Token getNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ jj_gen++;
+ return token;
+ }
+
+/** Get the specific Token. */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk() {
+ if ((jj_nt=token.next) == null)
+ return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+ else
+ return (jj_ntk = jj_nt.kind);
+ }
+
+ private java.util.List jj_expentries = new java.util.ArrayList();
+ private int[] jj_expentry;
+ private int jj_kind = -1;
+
+ /** Generate ParseException. */
+ public ParseException generateParseException() {
+ jj_expentries.clear();
+ boolean[] la1tokens = new boolean[23];
+ if (jj_kind >= 0) {
+ la1tokens[jj_kind] = true;
+ jj_kind = -1;
+ }
+ for (int i = 0; i < 3; i++) {
+ if (jj_la1[i] == jj_gen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jj_la1_0[i] & (1<",
+ "\",\"",
+ "\"-\"",
+ "",
+ "\"(\"",
+ "\")\"",
+ "",
+ "\"(\"",
+ "",
+ "",
+ "\"(\"",
+ "\")\"",
+ "",
+ "\"\\\"\"",
+ "",
+ "",
+ "\"\\\"\"",
+ "",
+ "",
+ "",
+ "\".\"",
+ "",
+ "",
+ };
+
+}
diff --git a/src/org/apache/james/mime4j/field/language/parser/ContentLanguageParserTokenManager.java b/src/org/apache/james/mime4j/field/language/parser/ContentLanguageParserTokenManager.java
new file mode 100644
index 000000000..1e66b9a86
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/language/parser/ContentLanguageParserTokenManager.java
@@ -0,0 +1,860 @@
+/* Generated By:JavaCC: Do not edit this line. ContentLanguageParserTokenManager.java */
+/****************************************************************
+ * 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.language.parser;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Token Manager. */
+public class ContentLanguageParserTokenManager implements ContentLanguageParserConstants
+{
+ // Keeps track of how many levels of comment nesting
+ // we've encountered. This is only used when the 2nd
+ // level is reached, for example ((this)), not (this).
+ // This is because the outermost level must be treated
+ // specially anyway, because the outermost ")" has a
+ // different token type than inner ")" instances.
+ int commentNest;
+
+ /** Debug output. */
+ public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
+ public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+ return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private int jjStopAtPos(int pos, int kind)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_0()
+{
+ switch(curChar)
+ {
+ case 34:
+ return jjStopAtPos(0, 13);
+ case 40:
+ return jjStopAtPos(0, 4);
+ case 44:
+ return jjStopAtPos(0, 1);
+ case 45:
+ return jjStopAtPos(0, 2);
+ case 46:
+ return jjStopAtPos(0, 20);
+ default :
+ return jjMoveNfa_0(4, 0);
+ }
+}
+private int jjMoveNfa_0(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 4;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 4:
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 19)
+ kind = 19;
+ jjCheckNAdd(3);
+ }
+ else if ((0x100002600L & l) != 0L)
+ {
+ if (kind > 3)
+ kind = 3;
+ jjCheckNAdd(0);
+ }
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(1);
+ }
+ break;
+ case 0:
+ if ((0x100002600L & l) == 0L)
+ break;
+ kind = 3;
+ jjCheckNAdd(0);
+ break;
+ case 1:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(1);
+ break;
+ case 3:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 19)
+ kind = 19;
+ jjCheckNAdd(3);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 4:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 19)
+ kind = 19;
+ jjCheckNAdd(3);
+ }
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAdd(2);
+ }
+ break;
+ case 2:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAdd(2);
+ break;
+ case 3:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 19)
+ kind = 19;
+ jjCheckNAdd(3);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_1(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_1(int pos, long active0)
+{
+ return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_1()
+{
+ switch(curChar)
+ {
+ case 40:
+ return jjStopAtPos(0, 7);
+ case 41:
+ return jjStopAtPos(0, 5);
+ default :
+ return jjMoveNfa_1(0, 0);
+ }
+}
+static final long[] jjbitVec0 = {
+ 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_1(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 8)
+ kind = 8;
+ break;
+ case 1:
+ if (kind > 6)
+ kind = 6;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 8)
+ kind = 8;
+ if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 6)
+ kind = 6;
+ break;
+ case 2:
+ if (kind > 8)
+ kind = 8;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 8)
+ kind = 8;
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 6)
+ kind = 6;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_3(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_3(int pos, long active0)
+{
+ return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_3()
+{
+ switch(curChar)
+ {
+ case 34:
+ return jjStopAtPos(0, 16);
+ default :
+ return jjMoveNfa_3(0, 0);
+ }
+}
+private int jjMoveNfa_3(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ case 2:
+ if ((0xfffffffbffffffffL & l) == 0L)
+ break;
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ break;
+ case 1:
+ if (kind > 14)
+ kind = 14;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((0xffffffffefffffffL & l) != 0L)
+ {
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ }
+ else if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 14)
+ kind = 14;
+ break;
+ case 2:
+ if ((0xffffffffefffffffL & l) == 0L)
+ break;
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ case 2:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 14)
+ kind = 14;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_2(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_2(int pos, long active0)
+{
+ return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_2()
+{
+ switch(curChar)
+ {
+ case 40:
+ return jjStopAtPos(0, 10);
+ case 41:
+ return jjStopAtPos(0, 11);
+ default :
+ return jjMoveNfa_2(0, 0);
+ }
+}
+private int jjMoveNfa_2(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 12)
+ kind = 12;
+ break;
+ case 1:
+ if (kind > 9)
+ kind = 9;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 12)
+ kind = 12;
+ if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 9)
+ kind = 9;
+ break;
+ case 2:
+ if (kind > 12)
+ kind = 12;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 12)
+ kind = 12;
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 9)
+ kind = 9;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+static final int[] jjnextStates = {
+};
+
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", "\54", "\55", null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, "\56", null, null, };
+
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+ "DEFAULT",
+ "INCOMMENT",
+ "NESTED_COMMENT",
+ "INQUOTEDSTRING",
+};
+
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+ -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1, -1, -1,
+};
+static final long[] jjtoToken = {
+ 0x1f0007L,
+};
+static final long[] jjtoSkip = {
+ 0x28L,
+};
+static final long[] jjtoSpecial = {
+ 0x8L,
+};
+static final long[] jjtoMore = {
+ 0xffd0L,
+};
+protected SimpleCharStream input_stream;
+private final int[] jjrounds = new int[4];
+private final int[] jjstateSet = new int[8];
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
+protected char curChar;
+/** Constructor. */
+public ContentLanguageParserTokenManager(SimpleCharStream stream){
+ if (SimpleCharStream.staticFlag)
+ throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+ input_stream = stream;
+}
+
+/** Constructor. */
+public ContentLanguageParserTokenManager(SimpleCharStream stream, int lexState){
+ this(stream);
+ SwitchTo(lexState);
+}
+
+/** Reinitialise parser. */
+public void ReInit(SimpleCharStream stream)
+{
+ jjmatchedPos = jjnewStateCnt = 0;
+ curLexState = defaultLexState;
+ input_stream = stream;
+ ReInitRounds();
+}
+private void ReInitRounds()
+{
+ int i;
+ jjround = 0x80000001;
+ for (i = 4; i-- > 0;)
+ jjrounds[i] = 0x80000000;
+}
+
+/** Reinitialise parser. */
+public void ReInit(SimpleCharStream stream, int lexState)
+{
+ ReInit(stream);
+ SwitchTo(lexState);
+}
+
+/** Switch to specified lex state. */
+public void SwitchTo(int lexState)
+{
+ if (lexState >= 4 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+ else
+ curLexState = lexState;
+}
+
+protected Token jjFillToken()
+{
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
+ String im = jjstrLiteralImages[jjmatchedKind];
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
+ return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+/** Get the next Token. */
+public Token getNextToken()
+{
+ Token specialToken = null;
+ Token matchedToken;
+ int curPos = 0;
+
+ EOFLoop :
+ for (;;)
+ {
+ try
+ {
+ curChar = input_stream.BeginToken();
+ }
+ catch(java.io.IOException e)
+ {
+ jjmatchedKind = 0;
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+ image = jjimage;
+ image.setLength(0);
+ jjimageLen = 0;
+
+ for (;;)
+ {
+ switch(curLexState)
+ {
+ case 0:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_0();
+ break;
+ case 1:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_1();
+ break;
+ case 2:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_2();
+ break;
+ case 3:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_3();
+ break;
+ }
+ if (jjmatchedKind != 0x7fffffff)
+ {
+ if (jjmatchedPos + 1 < curPos)
+ input_stream.backup(curPos - jjmatchedPos - 1);
+ if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ TokenLexicalActions(matchedToken);
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ return matchedToken;
+ }
+ else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ if (specialToken == null)
+ specialToken = matchedToken;
+ else
+ {
+ matchedToken.specialToken = specialToken;
+ specialToken = (specialToken.next = matchedToken);
+ }
+ }
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ continue EOFLoop;
+ }
+ MoreLexicalActions();
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ curPos = 0;
+ jjmatchedKind = 0x7fffffff;
+ try {
+ curChar = input_stream.readChar();
+ continue;
+ }
+ catch (java.io.IOException e1) { }
+ }
+ int error_line = input_stream.getEndLine();
+ int error_column = input_stream.getEndColumn();
+ String error_after = null;
+ boolean EOFSeen = false;
+ try { input_stream.readChar(); input_stream.backup(1); }
+ catch (java.io.IOException e1) {
+ EOFSeen = true;
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ error_line++;
+ error_column = 0;
+ }
+ else
+ error_column++;
+ }
+ if (!EOFSeen) {
+ input_stream.backup(1);
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ }
+ throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+ }
+ }
+}
+
+void MoreLexicalActions()
+{
+ jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
+ switch(jjmatchedKind)
+ {
+ case 6 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ case 7 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ commentNest = 1;
+ break;
+ case 9 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ case 10 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ ++commentNest;
+ break;
+ case 11 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
+ break;
+ case 13 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 1);
+ break;
+ case 14 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ default :
+ break;
+ }
+}
+void TokenLexicalActions(Token matchedToken)
+{
+ switch(jjmatchedKind)
+ {
+ case 16 :
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ matchedToken.image = image.substring(0, image.length() - 1);
+ break;
+ default :
+ break;
+ }
+}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
+}
diff --git a/src/org/apache/james/mime4j/field/language/parser/ParseException.java b/src/org/apache/james/mime4j/field/language/parser/ParseException.java
new file mode 100644
index 000000000..ad8c7aba8
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/language/parser/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************
+ * 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.language.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * This constructor is used by the method "generateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "tokenImage" set. The boolean
+ * flag "specialConstructor" is also set to true to indicate that
+ * this constructor was used to create this object.
+ * This constructor calls its super class with the empty string
+ * to force the "toString" method of parent class "Throwable" to
+ * print the error message in the form:
+ * ParseException:
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ String[] tokenImageVal
+ )
+ {
+ super("");
+ specialConstructor = true;
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Throwable". The fields "errorToken",
+ * "expectedTokenSequences", and "tokenImage" do not contain
+ * relevant information. The JavaCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() {
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
+ specialConstructor = false;
+ }
+
+ public ParseException(String message) {
+ super(message);
+ specialConstructor = false;
+ }
+
+ /**
+ * This variable determines which constructor was used to create
+ * this object and thereby affects the semantics of the
+ * "getMessage" method (see below).
+ */
+ protected boolean specialConstructor;
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "tokenImage" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public String[] tokenImage;
+
+ /**
+ * This method has the standard behavior when this object has been
+ * created using the standard constructors. Otherwise, it uses
+ * "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser), then this method is called during the printing
+ * of the final stack trace, and hence the correct error message
+ * gets displayed.
+ */
+ public String getMessage() {
+ if (!specialConstructor) {
+ return super.getMessage();
+ }
+ StringBuffer expected = new StringBuffer();
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.length; i++) {
+ if (maxSize < expectedTokenSequences[i].length) {
+ maxSize = expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+ expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+ expected.append("...");
+ }
+ expected.append(eol).append(" ");
+ }
+ String retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0) retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += add_escapes(tok.image);
+ tok = tok.next;
+ }
+ retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + eol;
+ if (expectedTokenSequences.length == 1) {
+ retval += "Was expecting:" + eol + " ";
+ } else {
+ retval += "Was expecting one of:" + eol + " ";
+ }
+ retval += expected.toString();
+ return retval;
+ }
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected String eol = System.getProperty("line.separator", "\n");
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ protected String add_escapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/language/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/language/parser/SimpleCharStream.java
new file mode 100644
index 000000000..a5bedb3af
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/language/parser/SimpleCharStream.java
@@ -0,0 +1,489 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.language.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+ public static final boolean staticFlag = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+/** Position in buffer. */
+ public int bufpos = -1;
+ protected int bufline[];
+ protected int bufcolumn[];
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected boolean prevCharIsCR = false;
+ protected boolean prevCharIsLF = false;
+
+ protected java.io.Reader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+ protected int tabSize = 8;
+
+ protected void setTabSize(int i) { tabSize = i; }
+ protected int getTabSize(int i) { return tabSize; }
+
+
+ protected void ExpandBuff(boolean wrapAround)
+ {
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
+
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
+
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() throws java.io.IOException
+ {
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
+ {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ }
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+/** Start. */
+ public char BeginToken() throws java.io.IOException
+ {
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
+
+ return c;
+ }
+
+ protected void UpdateLineColumn(char c)
+ {
+ column++;
+
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
+ line += (column = 1);
+ }
+
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+/** Read a character. */
+ public char readChar() throws java.io.IOException
+ {
+ if (inBuf > 0)
+ {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return c;
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndColumn
+ */
+
+ public int getColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndLine
+ */
+
+ public int getLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token end column number. */
+ public int getEndColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ /** Get token end line number. */
+ public int getEndLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token beginning column number. */
+ public int getBeginColumn() {
+ return bufcolumn[tokenBegin];
+ }
+
+ /** Get token beginning line number. */
+ public int getBeginLine() {
+ return bufline[tokenBegin];
+ }
+
+/** Backup a number of characters. */
+ public void backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.length)
+ {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+ /** Get token literal value. */
+ public String GetImage()
+ {
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
+ }
+
+ /** Get the suffix. */
+ public char[] GetSuffix(int len)
+ {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ /** Reset buffer when finished. */
+ public void Done()
+ {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /**
+ * Method to adjust line and column numbers for the start of a token.
+ */
+ public void adjustBeginLineColumn(int newLine, int newCol)
+ {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+
+}
+/* JavaCC - OriginalChecksum=d7aa8070376344ebe65083648cdac187 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/language/parser/Token.java b/src/org/apache/james/mime4j/field/language/parser/Token.java
new file mode 100644
index 000000000..53c3c120f
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/language/parser/Token.java
@@ -0,0 +1,149 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.language.parser;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * An integer that describes the kind of this token. This numbering
+ * system is determined by JavaCCParser, and a table of these numbers is
+ * stored in the file ...Constants.java.
+ */
+ public int kind;
+
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
+
+ /**
+ * The string image of the token.
+ */
+ public String image;
+
+ /**
+ * A reference to the next regular (non-special) token from the input
+ * stream. If this is the last token from the input stream, or if the
+ * token manager has not read tokens beyond this one, this field is
+ * set to null. This is true only if this token is also a regular
+ * token. Otherwise, see below for a description of the contents of
+ * this field.
+ */
+ public Token next;
+
+ /**
+ * This field is used to access special tokens that occur prior to this
+ * token, but after the immediately preceding regular (non-special) token.
+ * If there are no such special tokens, this field is set to null.
+ * When there are more than one such special token, this field refers
+ * to the last of these special tokens, which in turn refers to the next
+ * previous special token through its specialToken field, and so on
+ * until the first special token (whose specialToken field is null).
+ * The next fields of special tokens refer to other special tokens that
+ * immediately follow it (without an intervening regular token). If there
+ * is no such token, this field is null.
+ */
+ public Token specialToken;
+
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
+ /**
+ * Returns the image.
+ */
+ public String toString()
+ {
+ return image;
+ }
+
+ /**
+ * Returns a new Token object, by default. However, if you want, you
+ * can create and return subclass objects based on the value of ofKind.
+ * Simply add the cases to the switch for all those special cases.
+ * For example, if you have a subclass of Token called IDToken that
+ * you want to create if ofKind is ID, simply add something like :
+ *
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
+ *
+ * to the following switch statement. Then you can cast matchedToken
+ * variable to the appropriate type and use sit in your lexical actions.
+ */
+ public static Token newToken(int ofKind, String image)
+ {
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
+ }
+
+}
+/* JavaCC - OriginalChecksum=fcddf4a8d964b333f6f3396cdbc4bfc9 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/language/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/language/parser/TokenMgrError.java
new file mode 100644
index 000000000..ee9e7f6a0
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/language/parser/TokenMgrError.java
@@ -0,0 +1,165 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+/****************************************************************
+ * 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.language.parser;
+
+/** Token Manager Error. */
+public class TokenMgrError extends Error
+{
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
+
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
+
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
+
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
+
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
+
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
+
+ /*
+ * Constructors of various flavors follow.
+ */
+
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
+
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
+
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
+}
+/* JavaCC - OriginalChecksum=eb6019208b078108e75f1d3bfb81f2ca (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/mimeversion/parser/MimeVersionParser.java b/src/org/apache/james/mime4j/field/mimeversion/parser/MimeVersionParser.java
new file mode 100644
index 000000000..36e1b1e2e
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/mimeversion/parser/MimeVersionParser.java
@@ -0,0 +1,235 @@
+/* Generated By:JavaCC: Do not edit this line. MimeVersionParser.java */
+/****************************************************************
+ * 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.mimeversion.parser;
+
+public class MimeVersionParser implements MimeVersionParserConstants {
+ public static final int INITIAL_VERSION_VALUE = -1;
+ private int major=INITIAL_VERSION_VALUE;
+ private int minor=INITIAL_VERSION_VALUE;
+
+ public int getMinorVersion() {
+ return minor;
+ }
+
+ public int getMajorVersion() {
+ return major;
+ }
+
+ final public void parseLine() throws ParseException {
+ parse();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case 1:
+ jj_consume_token(1);
+ break;
+ default:
+ jj_la1[0] = jj_gen;
+ ;
+ }
+ jj_consume_token(2);
+ }
+
+ final public void parseAll() throws ParseException {
+ parse();
+ jj_consume_token(0);
+ }
+
+ final public void parse() throws ParseException {
+ Token major;
+ Token minor;
+ major = jj_consume_token(DIGITS);
+ jj_consume_token(DOT);
+ minor = jj_consume_token(DIGITS);
+ try {
+ this.major = Integer.parseInt(major.image);
+ this.minor = Integer.parseInt(minor.image);
+ } catch (NumberFormatException e) {
+ {if (true) throw new ParseException(e.getMessage());}
+ }
+ }
+
+ /** Generated Token Manager. */
+ public MimeVersionParserTokenManager token_source;
+ SimpleCharStream jj_input_stream;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
+ private int jj_ntk;
+ private int jj_gen;
+ final private int[] jj_la1 = new int[1];
+ static private int[] jj_la1_0;
+ static {
+ jj_la1_init_0();
+ }
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0x2,};
+ }
+
+ /** Constructor with InputStream. */
+ public MimeVersionParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+ /** Constructor with InputStream and supplied encoding */
+ public MimeVersionParser(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source = new MimeVersionParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 1; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream) {
+ ReInit(stream, null);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 1; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor. */
+ public MimeVersionParser(java.io.Reader stream) {
+ jj_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new MimeVersionParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 1; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader stream) {
+ jj_input_stream.ReInit(stream, 1, 1);
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 1; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor with generated Token Manager. */
+ public MimeVersionParser(MimeVersionParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 1; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(MimeVersionParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 1; i++) jj_la1[i] = -1;
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ if (token.kind == kind) {
+ jj_gen++;
+ return token;
+ }
+ token = oldToken;
+ jj_kind = kind;
+ throw generateParseException();
+ }
+
+
+/** Get the next Token. */
+ final public Token getNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ jj_gen++;
+ return token;
+ }
+
+/** Get the specific Token. */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk() {
+ if ((jj_nt=token.next) == null)
+ return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+ else
+ return (jj_ntk = jj_nt.kind);
+ }
+
+ private java.util.List jj_expentries = new java.util.ArrayList();
+ private int[] jj_expentry;
+ private int jj_kind = -1;
+
+ /** Generate ParseException. */
+ public ParseException generateParseException() {
+ jj_expentries.clear();
+ boolean[] la1tokens = new boolean[21];
+ if (jj_kind >= 0) {
+ la1tokens[jj_kind] = true;
+ jj_kind = -1;
+ }
+ for (int i = 0; i < 1; i++) {
+ if (jj_la1[i] == jj_gen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jj_la1_0[i] & (1<",
+ "\"\\r\"",
+ "\"\\n\"",
+ "",
+ "\"(\"",
+ "\")\"",
+ "",
+ "\"(\"",
+ "",
+ "",
+ "\"(\"",
+ "\")\"",
+ "",
+ "\"\\\"\"",
+ "",
+ "",
+ "\"\\\"\"",
+ "",
+ "\".\"",
+ "",
+ "",
+ };
+
+}
diff --git a/src/org/apache/james/mime4j/field/mimeversion/parser/MimeVersionParserTokenManager.java b/src/org/apache/james/mime4j/field/mimeversion/parser/MimeVersionParserTokenManager.java
new file mode 100644
index 000000000..92bff0b9a
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/mimeversion/parser/MimeVersionParserTokenManager.java
@@ -0,0 +1,824 @@
+/* Generated By:JavaCC: Do not edit this line. MimeVersionParserTokenManager.java */
+/****************************************************************
+ * 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.mimeversion.parser;
+
+/** Token Manager. */
+public class MimeVersionParserTokenManager implements MimeVersionParserConstants
+{
+ // Keeps track of how many levels of comment nesting
+ // we've encountered. This is only used when the 2nd
+ // level is reached, for example ((this)), not (this).
+ // This is because the outermost level must be treated
+ // specially anyway, because the outermost ")" has a
+ // different token type than inner ")" instances.
+ int commentNest;
+
+ /** Debug output. */
+ public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
+ public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_0(int pos, long active0)
+{
+ return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private int jjStopAtPos(int pos, int kind)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_0()
+{
+ switch(curChar)
+ {
+ case 10:
+ return jjStartNfaWithStates_0(0, 2, 0);
+ case 13:
+ return jjStartNfaWithStates_0(0, 1, 0);
+ case 34:
+ return jjStopAtPos(0, 13);
+ case 40:
+ return jjStopAtPos(0, 4);
+ case 46:
+ return jjStopAtPos(0, 18);
+ default :
+ return jjMoveNfa_0(2, 0);
+ }
+}
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return pos + 1; }
+ return jjMoveNfa_0(state, pos + 1);
+}
+private int jjMoveNfa_0(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 2;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 2:
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAdd(1);
+ }
+ else if ((0x100002600L & l) != 0L)
+ {
+ if (kind > 3)
+ kind = 3;
+ jjCheckNAdd(0);
+ }
+ break;
+ case 0:
+ if ((0x100002600L & l) == 0L)
+ break;
+ kind = 3;
+ jjCheckNAdd(0);
+ break;
+ case 1:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ kind = 17;
+ jjCheckNAdd(1);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 2 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_1(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_1(int pos, long active0)
+{
+ return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_1()
+{
+ switch(curChar)
+ {
+ case 40:
+ return jjStopAtPos(0, 7);
+ case 41:
+ return jjStopAtPos(0, 5);
+ default :
+ return jjMoveNfa_1(0, 0);
+ }
+}
+static final long[] jjbitVec0 = {
+ 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_1(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 8)
+ kind = 8;
+ break;
+ case 1:
+ if (kind > 6)
+ kind = 6;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 8)
+ kind = 8;
+ if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 6)
+ kind = 6;
+ break;
+ case 2:
+ if (kind > 8)
+ kind = 8;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 8)
+ kind = 8;
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 6)
+ kind = 6;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_3(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_3(int pos, long active0)
+{
+ return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_3()
+{
+ switch(curChar)
+ {
+ case 34:
+ return jjStopAtPos(0, 16);
+ default :
+ return jjMoveNfa_3(0, 0);
+ }
+}
+private int jjMoveNfa_3(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ case 2:
+ if ((0xfffffffbffffffffL & l) == 0L)
+ break;
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ break;
+ case 1:
+ if (kind > 14)
+ kind = 14;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((0xffffffffefffffffL & l) != 0L)
+ {
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ }
+ else if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 14)
+ kind = 14;
+ break;
+ case 2:
+ if ((0xffffffffefffffffL & l) == 0L)
+ break;
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ case 2:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 15)
+ kind = 15;
+ jjCheckNAdd(2);
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 14)
+ kind = 14;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private final int jjStopStringLiteralDfa_2(int pos, long active0)
+{
+ switch (pos)
+ {
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_2(int pos, long active0)
+{
+ return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
+}
+private int jjMoveStringLiteralDfa0_2()
+{
+ switch(curChar)
+ {
+ case 40:
+ return jjStopAtPos(0, 10);
+ case 41:
+ return jjStopAtPos(0, 11);
+ default :
+ return jjMoveNfa_2(0, 0);
+ }
+}
+private int jjMoveNfa_2(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 3;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 12)
+ kind = 12;
+ break;
+ case 1:
+ if (kind > 9)
+ kind = 9;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if (kind > 12)
+ kind = 12;
+ if (curChar == 92)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 1:
+ if (kind > 9)
+ kind = 9;
+ break;
+ case 2:
+ if (kind > 12)
+ kind = 12;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 12)
+ kind = 12;
+ break;
+ case 1:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 9)
+ kind = 9;
+ break;
+ default : break;
+ }
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+static final int[] jjnextStates = {
+};
+
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", "\15", "\12", null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, "\56", null, null, };
+
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+ "DEFAULT",
+ "INCOMMENT",
+ "NESTED_COMMENT",
+ "INQUOTEDSTRING",
+};
+
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+ -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1,
+};
+static final long[] jjtoToken = {
+ 0x70007L,
+};
+static final long[] jjtoSkip = {
+ 0x28L,
+};
+static final long[] jjtoSpecial = {
+ 0x8L,
+};
+static final long[] jjtoMore = {
+ 0xffd0L,
+};
+protected SimpleCharStream input_stream;
+private final int[] jjrounds = new int[3];
+private final int[] jjstateSet = new int[6];
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
+protected char curChar;
+/** Constructor. */
+public MimeVersionParserTokenManager(SimpleCharStream stream){
+ if (SimpleCharStream.staticFlag)
+ throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+ input_stream = stream;
+}
+
+/** Constructor. */
+public MimeVersionParserTokenManager(SimpleCharStream stream, int lexState){
+ this(stream);
+ SwitchTo(lexState);
+}
+
+/** Reinitialise parser. */
+public void ReInit(SimpleCharStream stream)
+{
+ jjmatchedPos = jjnewStateCnt = 0;
+ curLexState = defaultLexState;
+ input_stream = stream;
+ ReInitRounds();
+}
+private void ReInitRounds()
+{
+ int i;
+ jjround = 0x80000001;
+ for (i = 3; i-- > 0;)
+ jjrounds[i] = 0x80000000;
+}
+
+/** Reinitialise parser. */
+public void ReInit(SimpleCharStream stream, int lexState)
+{
+ ReInit(stream);
+ SwitchTo(lexState);
+}
+
+/** Switch to specified lex state. */
+public void SwitchTo(int lexState)
+{
+ if (lexState >= 4 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+ else
+ curLexState = lexState;
+}
+
+protected Token jjFillToken()
+{
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
+ String im = jjstrLiteralImages[jjmatchedKind];
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
+ return t;
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+/** Get the next Token. */
+public Token getNextToken()
+{
+ Token specialToken = null;
+ Token matchedToken;
+ int curPos = 0;
+
+ EOFLoop :
+ for (;;)
+ {
+ try
+ {
+ curChar = input_stream.BeginToken();
+ }
+ catch(java.io.IOException e)
+ {
+ jjmatchedKind = 0;
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+ image = jjimage;
+ image.setLength(0);
+ jjimageLen = 0;
+
+ for (;;)
+ {
+ switch(curLexState)
+ {
+ case 0:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_0();
+ break;
+ case 1:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_1();
+ break;
+ case 2:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_2();
+ break;
+ case 3:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_3();
+ break;
+ }
+ if (jjmatchedKind != 0x7fffffff)
+ {
+ if (jjmatchedPos + 1 < curPos)
+ input_stream.backup(curPos - jjmatchedPos - 1);
+ if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ TokenLexicalActions(matchedToken);
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ return matchedToken;
+ }
+ else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ if (specialToken == null)
+ specialToken = matchedToken;
+ else
+ {
+ matchedToken.specialToken = specialToken;
+ specialToken = (specialToken.next = matchedToken);
+ }
+ }
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ continue EOFLoop;
+ }
+ MoreLexicalActions();
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ curPos = 0;
+ jjmatchedKind = 0x7fffffff;
+ try {
+ curChar = input_stream.readChar();
+ continue;
+ }
+ catch (java.io.IOException e1) { }
+ }
+ int error_line = input_stream.getEndLine();
+ int error_column = input_stream.getEndColumn();
+ String error_after = null;
+ boolean EOFSeen = false;
+ try { input_stream.readChar(); input_stream.backup(1); }
+ catch (java.io.IOException e1) {
+ EOFSeen = true;
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ error_line++;
+ error_column = 0;
+ }
+ else
+ error_column++;
+ }
+ if (!EOFSeen) {
+ input_stream.backup(1);
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ }
+ throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+ }
+ }
+}
+
+void MoreLexicalActions()
+{
+ jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
+ switch(jjmatchedKind)
+ {
+ case 6 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ case 7 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ commentNest = 1;
+ break;
+ case 9 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ case 10 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ ++commentNest;
+ break;
+ case 11 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
+ break;
+ case 13 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 1);
+ break;
+ case 14 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ image.deleteCharAt(image.length() - 2);
+ break;
+ default :
+ break;
+ }
+}
+void TokenLexicalActions(Token matchedToken)
+{
+ switch(jjmatchedKind)
+ {
+ case 16 :
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ matchedToken.image = image.substring(0, image.length() - 1);
+ break;
+ default :
+ break;
+ }
+}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
+
+}
diff --git a/src/org/apache/james/mime4j/field/mimeversion/parser/ParseException.java b/src/org/apache/james/mime4j/field/mimeversion/parser/ParseException.java
new file mode 100644
index 000000000..26cd67905
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/mimeversion/parser/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************
+ * 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.mimeversion.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * This constructor is used by the method "generateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "tokenImage" set. The boolean
+ * flag "specialConstructor" is also set to true to indicate that
+ * this constructor was used to create this object.
+ * This constructor calls its super class with the empty string
+ * to force the "toString" method of parent class "Throwable" to
+ * print the error message in the form:
+ * ParseException:
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ String[] tokenImageVal
+ )
+ {
+ super("");
+ specialConstructor = true;
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Throwable". The fields "errorToken",
+ * "expectedTokenSequences", and "tokenImage" do not contain
+ * relevant information. The JavaCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() {
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
+ specialConstructor = false;
+ }
+
+ public ParseException(String message) {
+ super(message);
+ specialConstructor = false;
+ }
+
+ /**
+ * This variable determines which constructor was used to create
+ * this object and thereby affects the semantics of the
+ * "getMessage" method (see below).
+ */
+ protected boolean specialConstructor;
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "tokenImage" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public String[] tokenImage;
+
+ /**
+ * This method has the standard behavior when this object has been
+ * created using the standard constructors. Otherwise, it uses
+ * "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser), then this method is called during the printing
+ * of the final stack trace, and hence the correct error message
+ * gets displayed.
+ */
+ public String getMessage() {
+ if (!specialConstructor) {
+ return super.getMessage();
+ }
+ StringBuffer expected = new StringBuffer();
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.length; i++) {
+ if (maxSize < expectedTokenSequences[i].length) {
+ maxSize = expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+ expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+ expected.append("...");
+ }
+ expected.append(eol).append(" ");
+ }
+ String retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0) retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += add_escapes(tok.image);
+ tok = tok.next;
+ }
+ retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + eol;
+ if (expectedTokenSequences.length == 1) {
+ retval += "Was expecting:" + eol + " ";
+ } else {
+ retval += "Was expecting one of:" + eol + " ";
+ }
+ retval += expected.toString();
+ return retval;
+ }
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected String eol = System.getProperty("line.separator", "\n");
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ protected String add_escapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/mimeversion/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/mimeversion/parser/SimpleCharStream.java
new file mode 100644
index 000000000..df8cbfd92
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/mimeversion/parser/SimpleCharStream.java
@@ -0,0 +1,489 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.mimeversion.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+ public static final boolean staticFlag = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+/** Position in buffer. */
+ public int bufpos = -1;
+ protected int bufline[];
+ protected int bufcolumn[];
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected boolean prevCharIsCR = false;
+ protected boolean prevCharIsLF = false;
+
+ protected java.io.Reader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+ protected int tabSize = 8;
+
+ protected void setTabSize(int i) { tabSize = i; }
+ protected int getTabSize(int i) { return tabSize; }
+
+
+ protected void ExpandBuff(boolean wrapAround)
+ {
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
+
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
+
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() throws java.io.IOException
+ {
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
+ {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ }
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+/** Start. */
+ public char BeginToken() throws java.io.IOException
+ {
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
+
+ return c;
+ }
+
+ protected void UpdateLineColumn(char c)
+ {
+ column++;
+
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
+ line += (column = 1);
+ }
+
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+/** Read a character. */
+ public char readChar() throws java.io.IOException
+ {
+ if (inBuf > 0)
+ {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return c;
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndColumn
+ */
+
+ public int getColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndLine
+ */
+
+ public int getLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token end column number. */
+ public int getEndColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ /** Get token end line number. */
+ public int getEndLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token beginning column number. */
+ public int getBeginColumn() {
+ return bufcolumn[tokenBegin];
+ }
+
+ /** Get token beginning line number. */
+ public int getBeginLine() {
+ return bufline[tokenBegin];
+ }
+
+/** Backup a number of characters. */
+ public void backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.length)
+ {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+ /** Get token literal value. */
+ public String GetImage()
+ {
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
+ }
+
+ /** Get the suffix. */
+ public char[] GetSuffix(int len)
+ {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ /** Reset buffer when finished. */
+ public void Done()
+ {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /**
+ * Method to adjust line and column numbers for the start of a token.
+ */
+ public void adjustBeginLineColumn(int newLine, int newCol)
+ {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+
+}
+/* JavaCC - OriginalChecksum=2f0f9f97043c831084564dffb8cd0588 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/mimeversion/parser/Token.java b/src/org/apache/james/mime4j/field/mimeversion/parser/Token.java
new file mode 100644
index 000000000..c9a6c28ad
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/mimeversion/parser/Token.java
@@ -0,0 +1,149 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.mimeversion.parser;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * An integer that describes the kind of this token. This numbering
+ * system is determined by JavaCCParser, and a table of these numbers is
+ * stored in the file ...Constants.java.
+ */
+ public int kind;
+
+ /** The line number of the first character of this Token. */
+ public int beginLine;
+ /** The column number of the first character of this Token. */
+ public int beginColumn;
+ /** The line number of the last character of this Token. */
+ public int endLine;
+ /** The column number of the last character of this Token. */
+ public int endColumn;
+
+ /**
+ * The string image of the token.
+ */
+ public String image;
+
+ /**
+ * A reference to the next regular (non-special) token from the input
+ * stream. If this is the last token from the input stream, or if the
+ * token manager has not read tokens beyond this one, this field is
+ * set to null. This is true only if this token is also a regular
+ * token. Otherwise, see below for a description of the contents of
+ * this field.
+ */
+ public Token next;
+
+ /**
+ * This field is used to access special tokens that occur prior to this
+ * token, but after the immediately preceding regular (non-special) token.
+ * If there are no such special tokens, this field is set to null.
+ * When there are more than one such special token, this field refers
+ * to the last of these special tokens, which in turn refers to the next
+ * previous special token through its specialToken field, and so on
+ * until the first special token (whose specialToken field is null).
+ * The next fields of special tokens refer to other special tokens that
+ * immediately follow it (without an intervening regular token). If there
+ * is no such token, this field is null.
+ */
+ public Token specialToken;
+
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {}
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind)
+ {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image)
+ {
+ this.kind = kind;
+ this.image = image;
+ }
+
+ /**
+ * Returns the image.
+ */
+ public String toString()
+ {
+ return image;
+ }
+
+ /**
+ * Returns a new Token object, by default. However, if you want, you
+ * can create and return subclass objects based on the value of ofKind.
+ * Simply add the cases to the switch for all those special cases.
+ * For example, if you have a subclass of Token called IDToken that
+ * you want to create if ofKind is ID, simply add something like :
+ *
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
+ *
+ * to the following switch statement. Then you can cast matchedToken
+ * variable to the appropriate type and use sit in your lexical actions.
+ */
+ public static Token newToken(int ofKind, String image)
+ {
+ switch(ofKind)
+ {
+ default : return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind)
+ {
+ return newToken(ofKind, null);
+ }
+
+}
+/* JavaCC - OriginalChecksum=b8c5500461d21fb1e0fa5ff0e19aed83 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/mimeversion/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/mimeversion/parser/TokenMgrError.java
new file mode 100644
index 000000000..aeaa40c65
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/mimeversion/parser/TokenMgrError.java
@@ -0,0 +1,165 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+/****************************************************************
+ * 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.mimeversion.parser;
+
+/** Token Manager Error. */
+public class TokenMgrError extends Error
+{
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the serialized form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
+
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
+
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
+
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
+
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * EOFSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
+ return("Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"");
+ }
+
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ *
+ * "Internal Error : Please file a bug report .... "
+ *
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
+
+ /*
+ * Constructors of various flavors follow.
+ */
+
+ /** No arg constructor. */
+ public TokenMgrError() {
+ }
+
+ /** Constructor with message and reason. */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
+
+ /** Full Constructor. */
+ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
+ this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
+}
+/* JavaCC - OriginalChecksum=a2a21b7ea9b5401d9f73daabaea160b4 (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/structured/parser/ParseException.java b/src/org/apache/james/mime4j/field/structured/parser/ParseException.java
new file mode 100644
index 000000000..bbdb642b8
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/structured/parser/ParseException.java
@@ -0,0 +1,220 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
+/****************************************************************
+ * 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.structured.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * Changes for Mime4J:
+ * extends org.apache.james.mime4j.field.ParseException
+ * added serialVersionUID
+ * added constructor ParseException(Throwable)
+ * default detail message is "Cannot parse field"
+ */
+public class ParseException extends org.apache.james.mime4j.dom.field.ParseException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * This constructor is used by the method "generateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "tokenImage" set. The boolean
+ * flag "specialConstructor" is also set to true to indicate that
+ * this constructor was used to create this object.
+ * This constructor calls its super class with the empty string
+ * to force the "toString" method of parent class "Throwable" to
+ * print the error message in the form:
+ * ParseException:
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ String[] tokenImageVal
+ )
+ {
+ super("");
+ specialConstructor = true;
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Throwable". The fields "errorToken",
+ * "expectedTokenSequences", and "tokenImage" do not contain
+ * relevant information. The JavaCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() {
+ super("Cannot parse field");
+ specialConstructor = false;
+ }
+
+ public ParseException(Throwable cause) {
+ super(cause);
+ specialConstructor = false;
+ }
+
+ public ParseException(String message) {
+ super(message);
+ specialConstructor = false;
+ }
+
+ /**
+ * This variable determines which constructor was used to create
+ * this object and thereby affects the semantics of the
+ * "getMessage" method (see below).
+ */
+ protected boolean specialConstructor;
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "tokenImage" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public String[] tokenImage;
+
+ /**
+ * This method has the standard behavior when this object has been
+ * created using the standard constructors. Otherwise, it uses
+ * "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser), then this method is called during the printing
+ * of the final stack trace, and hence the correct error message
+ * gets displayed.
+ */
+ public String getMessage() {
+ if (!specialConstructor) {
+ return super.getMessage();
+ }
+ StringBuffer expected = new StringBuffer();
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.length; i++) {
+ if (maxSize < expectedTokenSequences[i].length) {
+ maxSize = expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+ expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+ expected.append("...");
+ }
+ expected.append(eol).append(" ");
+ }
+ String retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0) retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += add_escapes(tok.image);
+ tok = tok.next;
+ }
+ retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + eol;
+ if (expectedTokenSequences.length == 1) {
+ retval += "Was expecting:" + eol + " ";
+ } else {
+ retval += "Was expecting one of:" + eol + " ";
+ }
+ retval += expected.toString();
+ return retval;
+ }
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected String eol = System.getProperty("line.separator", "\n");
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ protected String add_escapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i))
+ {
+ case 0 :
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+}
diff --git a/src/org/apache/james/mime4j/field/structured/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/structured/parser/SimpleCharStream.java
new file mode 100644
index 000000000..6e340c96b
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/structured/parser/SimpleCharStream.java
@@ -0,0 +1,489 @@
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/****************************************************************
+ * 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.structured.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream
+{
+/** Whether parser is static. */
+ public static final boolean staticFlag = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+/** Position in buffer. */
+ public int bufpos = -1;
+ protected int bufline[];
+ protected int bufcolumn[];
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected boolean prevCharIsCR = false;
+ protected boolean prevCharIsLF = false;
+
+ protected java.io.Reader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+ protected int tabSize = 8;
+
+ protected void setTabSize(int i) { tabSize = i; }
+ protected int getTabSize(int i) { return tabSize; }
+
+
+ protected void ExpandBuff(boolean wrapAround)
+ {
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
+
+ try
+ {
+ if (wrapAround)
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos += (bufsize - tokenBegin));
+ }
+ else
+ {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = (bufpos -= tokenBegin);
+ }
+ }
+ catch (Throwable t)
+ {
+ throw new Error(t.getMessage());
+ }
+
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() throws java.io.IOException
+ {
+ if (maxNextCharInd == available)
+ {
+ if (available == bufsize)
+ {
+ if (tokenBegin > 2048)
+ {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ }
+ else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ }
+ else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1)
+ {
+ inputStream.close();
+ throw new java.io.IOException();
+ }
+ else
+ maxNextCharInd += i;
+ return;
+ }
+ catch(java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+/** Start. */
+ public char BeginToken() throws java.io.IOException
+ {
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
+
+ return c;
+ }
+
+ protected void UpdateLineColumn(char c)
+ {
+ column++;
+
+ if (prevCharIsLF)
+ {
+ prevCharIsLF = false;
+ line += (column = 1);
+ }
+ else if (prevCharIsCR)
+ {
+ prevCharIsCR = false;
+ if (c == '\n')
+ {
+ prevCharIsLF = true;
+ }
+ else
+ line += (column = 1);
+ }
+
+ switch (c)
+ {
+ case '\r' :
+ prevCharIsCR = true;
+ break;
+ case '\n' :
+ prevCharIsLF = true;
+ break;
+ case '\t' :
+ column--;
+ column += (tabSize - (column % tabSize));
+ break;
+ default :
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+/** Read a character. */
+ public char readChar() throws java.io.IOException
+ {
+ if (inBuf > 0)
+ {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return c;
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndColumn
+ */
+
+ public int getColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndLine
+ */
+
+ public int getLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token end column number. */
+ public int getEndColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ /** Get token end line number. */
+ public int getEndLine() {
+ return bufline[bufpos];
+ }
+
+ /** Get token beginning column number. */
+ public int getBeginColumn() {
+ return bufcolumn[tokenBegin];
+ }
+
+ /** Get token beginning line number. */
+ public int getBeginLine() {
+ return bufline[tokenBegin];
+ }
+
+/** Backup a number of characters. */
+ public void backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.Reader dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.length)
+ {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ this(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Constructor. */
+ public SimpleCharStream(java.io.InputStream dstream)
+ {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize)
+ {
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, 1, 1, 4096);
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream)
+ {
+ ReInit(dstream, 1, 1, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException
+ {
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn)
+ {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+ /** Get token literal value. */
+ public String GetImage()
+ {
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
+ }
+
+ /** Get the suffix. */
+ public char[] GetSuffix(int len)
+ {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else
+ {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ /** Reset buffer when finished. */
+ public void Done()
+ {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /**
+ * Method to adjust line and column numbers for the start of a token.
+ */
+ public void adjustBeginLineColumn(int newLine, int newCol)
+ {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin)
+ {
+ len = bufpos - tokenBegin + inBuf + 1;
+ }
+ else
+ {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
+ {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len)
+ {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len)
+ {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+
+}
+/* JavaCC - OriginalChecksum=33b0886501084acf0a503d419221290d (do not edit this line) */
diff --git a/src/org/apache/james/mime4j/field/structured/parser/StructuredFieldParser.java b/src/org/apache/james/mime4j/field/structured/parser/StructuredFieldParser.java
new file mode 100644
index 000000000..7d7a166db
--- /dev/null
+++ b/src/org/apache/james/mime4j/field/structured/parser/StructuredFieldParser.java
@@ -0,0 +1,289 @@
+/* Generated By:JavaCC: Do not edit this line. StructuredFieldParser.java */
+/****************************************************************
+ * 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.structured.parser;
+
+/**
+ * Parses generic structure fields.
+ * Unfolds and removes comments.
+ */
+public class StructuredFieldParser implements StructuredFieldParserConstants {
+
+ private boolean preserveFolding = false;
+
+ /**
+ * Should the \r\n folding sequence be preserved?
+ */
+ public boolean isFoldingPreserved() {
+ return preserveFolding;
+ }
+
+ /**
+ * Sets whether the \r\n folding sequence should be preserved.
+ */
+ public void setFoldingPreserved(boolean preserveFolding) {
+ this.preserveFolding = preserveFolding;
+ }
+
+ /**
+ * Unfolds the input and removes comments.
+ * @return unfolded header value with comments removed
+ */
+ public String parse() throws ParseException {
+ try {
+ return doParse();
+ } catch (TokenMgrError e) {
+ // An issue with the TOKENiser
+ // but it's not polite to throw an Error
+ // when executing on a server
+ throw new ParseException(e);
+ }
+ }
+
+ final private String doParse() throws ParseException {
+ Token t;
+ StringBuffer buffer = new StringBuffer(50);
+ boolean whitespace = false;
+ boolean first = true;
+ label_1:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case STRING_CONTENT:
+ case FOLD:
+ case QUOTEDSTRING:
+ case WS:
+ case CONTENT:
+ ;
+ break;
+ default:
+ jj_la1[0] = jj_gen;
+ break label_1;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case CONTENT:
+ t = jj_consume_token(CONTENT);
+ if (first) {
+ first = false;
+ } else if (whitespace) {
+ buffer.append(" ");
+ whitespace = false;
+ }
+ buffer.append(t.image);
+ break;
+ case STRING_CONTENT:
+ t = jj_consume_token(STRING_CONTENT);
+ buffer.append(t.image);
+ break;
+ case QUOTEDSTRING:
+ t = jj_consume_token(QUOTEDSTRING);
+ if (first) {
+ first = false;
+ } else if (whitespace) {
+ buffer.append(" ");
+ whitespace = false;
+ }
+ buffer.append(t.image);
+ break;
+ case FOLD:
+ t = jj_consume_token(FOLD);
+ if (preserveFolding) buffer.append("\u005cr\u005cn");
+ break;
+ case WS:
+ t = jj_consume_token(WS);
+ whitespace = true;
+ break;
+ default:
+ jj_la1[1] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ {if (true) return buffer.toString();}
+ throw new Error("Missing return statement in function");
+ }
+
+ /** Generated Token Manager. */
+ public StructuredFieldParserTokenManager token_source;
+ SimpleCharStream jj_input_stream;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
+ private int jj_ntk;
+ private int jj_gen;
+ final private int[] jj_la1 = new int[2];
+ static private int[] jj_la1_0;
+ static {
+ jj_la1_init_0();
+ }
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0xf800,0xf800,};
+ }
+
+ /** Constructor with InputStream. */
+ public StructuredFieldParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+ /** Constructor with InputStream and supplied encoding */
+ public StructuredFieldParser(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source = new StructuredFieldParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 2; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream) {
+ ReInit(stream, null);
+ }
+ /** Reinitialise. */
+ public void ReInit(java.io.InputStream stream, String encoding) {
+ try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 2; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor. */
+ public StructuredFieldParser(java.io.Reader stream) {
+ jj_input_stream = new SimpleCharStream(stream, 1, 1);
+ token_source = new StructuredFieldParserTokenManager(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 2; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(java.io.Reader stream) {
+ jj_input_stream.ReInit(stream, 1, 1);
+ token_source.ReInit(jj_input_stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 2; i++) jj_la1[i] = -1;
+ }
+
+ /** Constructor with generated Token Manager. */
+ public StructuredFieldParser(StructuredFieldParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 2; i++) jj_la1[i] = -1;
+ }
+
+ /** Reinitialise. */
+ public void ReInit(StructuredFieldParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 2; i++) jj_la1[i] = -1;
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ if (token.kind == kind) {
+ jj_gen++;
+ return token;
+ }
+ token = oldToken;
+ jj_kind = kind;
+ throw generateParseException();
+ }
+
+
+/** Get the next Token. */
+ final public Token getNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ jj_gen++;
+ return token;
+ }
+
+/** Get the specific Token. */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk() {
+ if ((jj_nt=token.next) == null)
+ return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+ else
+ return (jj_ntk = jj_nt.kind);
+ }
+
+ private java.util.List jj_expentries = new java.util.ArrayList();
+ private int[] jj_expentry;
+ private int jj_kind = -1;
+
+ /** Generate ParseException. */
+ public ParseException generateParseException() {
+ jj_expentries.clear();
+ boolean[] la1tokens = new boolean[18];
+ if (jj_kind >= 0) {
+ la1tokens[jj_kind] = true;
+ jj_kind = -1;
+ }
+ for (int i = 0; i < 2; i++) {
+ if (jj_la1[i] == jj_gen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jj_la1_0[i] & (1<