summaryrefslogtreecommitdiff
path: root/src/org/apache/commons/net/io
diff options
context:
space:
mode:
authorJoe Robinson <joe@lc8n.com>2010-10-27 21:31:44 +0100
committerJoe Robinson <joe@lc8n.com>2010-10-27 21:31:44 +0100
commit01c75a7aa09d0d9fd7a4c61f952aaa93972e7c99 (patch)
tree9f5ea5af583c0e082d7f5a5dbd30c644ad6b6166 /src/org/apache/commons/net/io
Reset eclipse workspace (commit hopefully changes nothing)
Diffstat (limited to 'src/org/apache/commons/net/io')
-rw-r--r--src/org/apache/commons/net/io/CopyStreamAdapter.java122
-rw-r--r--src/org/apache/commons/net/io/CopyStreamEvent.java98
-rw-r--r--src/org/apache/commons/net/io/CopyStreamException.java71
-rw-r--r--src/org/apache/commons/net/io/CopyStreamListener.java72
-rw-r--r--src/org/apache/commons/net/io/DotTerminatedMessageReader.java280
-rw-r--r--src/org/apache/commons/net/io/DotTerminatedMessageWriter.java215
-rw-r--r--src/org/apache/commons/net/io/FromNetASCIIInputStream.java205
-rw-r--r--src/org/apache/commons/net/io/FromNetASCIIOutputStream.java174
-rw-r--r--src/org/apache/commons/net/io/SocketInputStream.java69
-rw-r--r--src/org/apache/commons/net/io/SocketOutputStream.java89
-rw-r--r--src/org/apache/commons/net/io/ToNetASCIIInputStream.java181
-rw-r--r--src/org/apache/commons/net/io/ToNetASCIIOutputStream.java119
-rw-r--r--src/org/apache/commons/net/io/Util.java334
13 files changed, 2029 insertions, 0 deletions
diff --git a/src/org/apache/commons/net/io/CopyStreamAdapter.java b/src/org/apache/commons/net/io/CopyStreamAdapter.java
new file mode 100644
index 0000000..0679d23
--- /dev/null
+++ b/src/org/apache/commons/net/io/CopyStreamAdapter.java
@@ -0,0 +1,122 @@
+/*
+ * 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.commons.net.io;
+
+import java.util.EventListener;
+
+import org.apache.commons.net.util.ListenerList;
+
+/**
+ * The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners
+ * when either of its bytesTransferred() methods are called. Its purpose
+ * is to facilitate the notification of the progress of a copy operation
+ * performed by one of the static copyStream() methods in
+ * org.apache.commons.io.Util to multiple listeners. The static
+ * copyStream() methods invoke the
+ * bytesTransfered(long, int) of a CopyStreamListener for performance
+ * reasons and also because multiple listeners cannot be registered given
+ * that the methods are static.
+ * <p>
+ * <p>
+ * @see CopyStreamEvent
+ * @see CopyStreamListener
+ * @see Util
+ * @author <a href="mailto:savarese@apache.org">Daniel F. Savarese</a>
+ * @version $Id: CopyStreamAdapter.java 489397 2006-12-21 16:28:51Z rwinston $
+ */
+public class CopyStreamAdapter implements CopyStreamListener
+{
+ private ListenerList internalListeners;
+
+ /**
+ * Creates a new copyStreamAdapter.
+ */
+ public CopyStreamAdapter()
+ {
+ internalListeners = new ListenerList();
+ }
+
+ /**
+ * This method is invoked by a CopyStreamEvent source after copying
+ * a block of bytes from a stream. The CopyStreamEvent will contain
+ * the total number of bytes transferred so far and the number of bytes
+ * transferred in the last write. The CopyStreamAdapater will relay
+ * the event to all of its registered listeners, listing itself as the
+ * source of the event.
+ * @param event The CopyStreamEvent fired by the copying of a block of
+ * bytes.
+ */
+ public void bytesTransferred(CopyStreamEvent event)
+ {
+ bytesTransferred(event.getTotalBytesTransferred(),
+ event.getBytesTransferred(),
+ event.getStreamSize());
+ }
+
+ /**
+ * This method is not part of the JavaBeans model and is used by the
+ * static methods in the org.apache.commons.io.Util class for efficiency.
+ * It is invoked after a block of bytes to inform the listener of the
+ * transfer. The CopyStreamAdapater will create a CopyStreamEvent
+ * from the arguments and relay the event to all of its registered
+ * listeners, listing itself as the source of the event.
+ * @param totalBytesTransferred The total number of bytes transferred
+ * so far by the copy operation.
+ * @param bytesTransferred The number of bytes copied by the most recent
+ * write.
+ * @param streamSize The number of bytes in the stream being copied.
+ * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if
+ * the size is unknown.
+ */
+ public void bytesTransferred(long totalBytesTransferred,
+ int bytesTransferred, long streamSize)
+ {
+ CopyStreamEvent event;
+
+ event = new CopyStreamEvent(this,
+ totalBytesTransferred,
+ bytesTransferred,
+ streamSize);
+
+ for (EventListener listener : internalListeners)
+ {
+ ((CopyStreamListener) (listener)).bytesTransferred(event);
+ }
+ }
+
+ /**
+ * Registers a CopyStreamListener to receive CopyStreamEvents.
+ * Although this method is not declared to be synchronized, it is
+ * implemented in a thread safe manner.
+ * @param listener The CopyStreamlistener to register.
+ */
+ public void addCopyStreamListener(CopyStreamListener listener)
+ {
+ internalListeners.addListener(listener);
+ }
+
+ /**
+ * Unregisters a CopyStreamListener. Although this method is not
+ * synchronized, it is implemented in a thread safe manner.
+ * @param listener The CopyStreamlistener to unregister.
+ */
+ public void removeCopyStreamListener(CopyStreamListener listener)
+ {
+ internalListeners.removeListener(listener);
+ }
+}
diff --git a/src/org/apache/commons/net/io/CopyStreamEvent.java b/src/org/apache/commons/net/io/CopyStreamEvent.java
new file mode 100644
index 0000000..d7d0ec3
--- /dev/null
+++ b/src/org/apache/commons/net/io/CopyStreamEvent.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.commons.net.io;
+
+import java.util.EventObject;
+
+/**
+ * A CopyStreamEvent is triggered after every write performed by a
+ * stream copying operation. The event stores the number of bytes
+ * transferred by the write triggering the event as well as the total
+ * number of bytes transferred so far by the copy operation.
+ * <p>
+ * <p>
+ * @see CopyStreamListener
+ * @see CopyStreamAdapter
+ * @see Util
+ * @author <a href="mailto:savarese@apache.org">Daniel F. Savarese</a>
+ * @version $Id: CopyStreamEvent.java 489397 2006-12-21 16:28:51Z rwinston $
+ */
+public class CopyStreamEvent extends EventObject
+{
+ /**
+ * Constant used to indicate the stream size is unknown.
+ */
+ public static final long UNKNOWN_STREAM_SIZE = -1;
+
+ private int bytesTransferred;
+ private long totalBytesTransferred;
+ private long streamSize;
+
+ /**
+ * Creates a new CopyStreamEvent instance.
+ * @param source The source of the event.
+ * @param totalBytesTransferred The total number of bytes transferred so
+ * far during a copy operation.
+ * @param bytesTransferred The number of bytes transferred during the
+ * write that triggered the CopyStreamEvent.
+ * @param streamSize The number of bytes in the stream being copied.
+ * This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the
+ * size is unknown.
+ */
+ public CopyStreamEvent(Object source, long totalBytesTransferred,
+ int bytesTransferred, long streamSize)
+ {
+ super(source);
+ this.bytesTransferred = bytesTransferred;
+ this.totalBytesTransferred = totalBytesTransferred;
+ this.streamSize = streamSize;
+ }
+
+ /**
+ * Returns the number of bytes transferred by the write that triggered
+ * the event.
+ * @return The number of bytes transferred by the write that triggered
+ * the vent.
+ */
+ public int getBytesTransferred()
+ {
+ return bytesTransferred;
+ }
+
+ /**
+ * Returns the total number of bytes transferred so far by the copy
+ * operation.
+ * @return The total number of bytes transferred so far by the copy
+ * operation.
+ */
+ public long getTotalBytesTransferred()
+ {
+ return totalBytesTransferred;
+ }
+
+ /**
+ * Returns the size of the stream being copied.
+ * This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the
+ * size is unknown.
+ * @return The size of the stream being copied.
+ */
+ public long getStreamSize()
+ {
+ return streamSize;
+ }
+}
diff --git a/src/org/apache/commons/net/io/CopyStreamException.java b/src/org/apache/commons/net/io/CopyStreamException.java
new file mode 100644
index 0000000..8d34145
--- /dev/null
+++ b/src/org/apache/commons/net/io/CopyStreamException.java
@@ -0,0 +1,71 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.IOException;
+
+/**
+ * The CopyStreamException class is thrown by the org.apache.commons.io.Util
+ * copyStream() methods. It stores the number of bytes confirmed to
+ * have been transferred before an I/O error as well as the IOException
+ * responsible for the failure of a copy operation.
+ * @see Util
+ * @author <a href="mailto:savarese@apache.org">Daniel F. Savarese</a>
+ * @version $Id: CopyStreamException.java 489397 2006-12-21 16:28:51Z rwinston $
+ */
+public class CopyStreamException extends IOException
+{
+ private long totalBytesTransferred;
+ private IOException ioException;
+
+ /**
+ * Creates a new CopyStreamException instance.
+ * @param message A message describing the error.
+ * @param bytesTransferred The total number of bytes transferred before
+ * an exception was thrown in a copy operation.
+ * @param exception The IOException thrown during a copy operation.
+ */
+ public CopyStreamException(String message,
+ long bytesTransferred,
+ IOException exception)
+ {
+ super(message);
+ totalBytesTransferred = bytesTransferred;
+ ioException = exception;
+ }
+
+ /**
+ * Returns the total number of bytes confirmed to have
+ * been transferred by a failed copy operation.
+ * @return The total number of bytes confirmed to have
+ * been transferred by a failed copy operation.
+ */
+ public long getTotalBytesTransferred()
+ {
+ return totalBytesTransferred;
+ }
+
+ /**
+ * Returns the IOException responsible for the failure of a copy operation.
+ * @return The IOException responsible for the failure of a copy operation.
+ */
+ public IOException getIOException()
+ {
+ return ioException;
+ }
+}
diff --git a/src/org/apache/commons/net/io/CopyStreamListener.java b/src/org/apache/commons/net/io/CopyStreamListener.java
new file mode 100644
index 0000000..9e97fb9
--- /dev/null
+++ b/src/org/apache/commons/net/io/CopyStreamListener.java
@@ -0,0 +1,72 @@
+/*
+ * 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.commons.net.io;
+
+import java.util.EventListener;
+
+/**
+ * The CopyStreamListener class can accept CopyStreamEvents to keep track
+ * of the progress of a stream copying operation. However, it is currently
+ * not used that way within NetComponents for performance reasons. Rather
+ * the bytesTransferred(long, int) method is called directly rather than
+ * passing an event to bytesTransferred(CopyStreamEvent), saving the creation
+ * of a CopyStreamEvent instance. Also, the only place where
+ * CopyStreamListener is currently used within NetComponents is in the
+ * static methods of the uninstantiable org.apache.commons.io.Util class, which
+ * would preclude the use of addCopyStreamListener and
+ * removeCopyStreamListener methods. However, future additions may use the
+ * JavaBean event model, which is why the hooks have been included from the
+ * beginning.
+ * <p>
+ * <p>
+ * @see CopyStreamEvent
+ * @see CopyStreamAdapter
+ * @see Util
+ * @author <a href="mailto:savarese@apache.org">Daniel F. Savarese</a>
+ * @version $Id: CopyStreamListener.java 489397 2006-12-21 16:28:51Z rwinston $
+ */
+public interface CopyStreamListener extends EventListener
+{
+ /**
+ * This method is invoked by a CopyStreamEvent source after copying
+ * a block of bytes from a stream. The CopyStreamEvent will contain
+ * the total number of bytes transferred so far and the number of bytes
+ * transferred in the last write.
+ * @param event The CopyStreamEvent fired by the copying of a block of
+ * bytes.
+ */
+ public void bytesTransferred(CopyStreamEvent event);
+
+
+ /**
+ * This method is not part of the JavaBeans model and is used by the
+ * static methods in the org.apache.commons.io.Util class for efficiency.
+ * It is invoked after a block of bytes to inform the listener of the
+ * transfer.
+ * @param totalBytesTransferred The total number of bytes transferred
+ * so far by the copy operation.
+ * @param bytesTransferred The number of bytes copied by the most recent
+ * write.
+ * @param streamSize The number of bytes in the stream being copied.
+ * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if
+ * the size is unknown.
+ */
+ public void bytesTransferred(long totalBytesTransferred,
+ int bytesTransferred,
+ long streamSize);
+}
diff --git a/src/org/apache/commons/net/io/DotTerminatedMessageReader.java b/src/org/apache/commons/net/io/DotTerminatedMessageReader.java
new file mode 100644
index 0000000..c0f344d
--- /dev/null
+++ b/src/org/apache/commons/net/io/DotTerminatedMessageReader.java
@@ -0,0 +1,280 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.Reader;
+
+/**
+ * DotTerminatedMessageReader is a class used to read messages from a
+ * server that are terminated by a single dot followed by a
+ * &lt;CR&gt;&lt;LF&gt;
+ * sequence and with double dots appearing at the begining of lines which
+ * do not signal end of message yet start with a dot. Various Internet
+ * protocols such as NNTP and POP3 produce messages of this type.
+ * <p>
+ * This class handles stripping of the duplicate period at the beginning
+ * of lines starting with a period, converts NETASCII newlines to the
+ * local line separator format, truncates the end of message indicator,
+ * and ensures you cannot read past the end of the message.
+ * @author <a href="mailto:savarese@apache.org">Daniel F. Savarese</a>
+ * @version $Id: DotTerminatedMessageReader.java 636825 2008-03-13 18:34:52Z sebb $
+ */
+public final class DotTerminatedMessageReader extends Reader
+{
+ private static final String LS;
+ private static final char[] LS_CHARS;
+
+ static
+ {
+ LS = System.getProperty("line.separator");
+ LS_CHARS = LS.toCharArray();
+ }
+
+ private boolean atBeginning;
+ private boolean eof;
+ private int pos;
+ private char[] internalBuffer;
+ private PushbackReader internalReader;
+
+ /**
+ * Creates a DotTerminatedMessageReader that wraps an existing Reader
+ * input source.
+ * @param reader The Reader input source containing the message.
+ */
+ public DotTerminatedMessageReader(Reader reader)
+ {
+ super(reader);
+ internalBuffer = new char[LS_CHARS.length + 3];
+ pos = internalBuffer.length;
+ // Assumes input is at start of message
+ atBeginning = true;
+ eof = false;
+ internalReader = new PushbackReader(reader);
+ }
+
+ /**
+ * Reads and returns the next character in the message. If the end of the
+ * message has been reached, returns -1. Note that a call to this method
+ * may result in multiple reads from the underlying input stream to decode
+ * the message properly (removing doubled dots and so on). All of
+ * this is transparent to the programmer and is only mentioned for
+ * completeness.
+ * @return The next character in the message. Returns -1 if the end of the
+ * message has been reached.
+ * @exception IOException If an error occurs while reading the underlying
+ * stream.
+ */
+ @Override
+ public int read() throws IOException
+ {
+ int ch;
+
+ synchronized (lock)
+ {
+ if (pos < internalBuffer.length)
+ {
+ return internalBuffer[pos++];
+ }
+
+ if (eof)
+ {
+ return -1;
+ }
+
+ if ((ch = internalReader.read()) == -1)
+ {
+ eof = true;
+ return -1;
+ }
+
+ if (atBeginning)
+ {
+ atBeginning = false;
+ if (ch == '.')
+ {
+ ch = internalReader.read();
+
+ if (ch != '.')
+ {
+ // read newline
+ eof = true;
+ internalReader.read();
+ return -1;
+ }
+ else
+ {
+ return '.';
+ }
+ }
+ }
+
+ if (ch == '\r')
+ {
+ ch = internalReader.read();
+
+ if (ch == '\n')
+ {
+ ch = internalReader.read();
+
+ if (ch == '.')
+ {
+ ch = internalReader.read();
+
+ if (ch != '.')
+ {
+ // read newline and indicate end of file
+ internalReader.read();
+ eof = true;
+ }
+ else
+ {
+ internalBuffer[--pos] = (char) ch;
+ }
+ }
+ else
+ {
+ internalReader.unread(ch);
+ }
+
+ pos -= LS_CHARS.length;
+ System.arraycopy(LS_CHARS, 0, internalBuffer, pos,
+ LS_CHARS.length);
+ ch = internalBuffer[pos++];
+ }
+ else
+ {
+ internalBuffer[--pos] = (char) ch;
+ return '\r';
+ }
+ }
+
+ return ch;
+ }
+ }
+
+ /**
+ * Reads the next characters from the message into an array and
+ * returns the number of characters read. Returns -1 if the end of the
+ * message has been reached.
+ * @param buffer The character array in which to store the characters.
+ * @return The number of characters read. Returns -1 if the
+ * end of the message has been reached.
+ * @exception IOException If an error occurs in reading the underlying
+ * stream.
+ */
+ @Override
+ public int read(char[] buffer) throws IOException
+ {
+ return read(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Reads the next characters from the message into an array and
+ * returns the number of characters read. Returns -1 if the end of the
+ * message has been reached. The characters are stored in the array
+ * starting from the given offset and up to the length specified.
+ * @param buffer The character array in which to store the characters.
+ * @param offset The offset into the array at which to start storing
+ * characters.
+ * @param length The number of characters to read.
+ * @return The number of characters read. Returns -1 if the
+ * end of the message has been reached.
+ * @exception IOException If an error occurs in reading the underlying
+ * stream.
+ */
+ @Override
+ public int read(char[] buffer, int offset, int length) throws IOException
+ {
+ int ch, off;
+ synchronized (lock)
+ {
+ if (length < 1)
+ {
+ return 0;
+ }
+ if ((ch = read()) == -1)
+ {
+ return -1;
+ }
+ off = offset;
+
+ do
+ {
+ buffer[offset++] = (char) ch;
+ }
+ while (--length > 0 && (ch = read()) != -1);
+
+ return (offset - off);
+ }
+ }
+
+ /**
+ * Determines if the message is ready to be read.
+ * @return True if the message is ready to be read, false if not.
+ * @exception IOException If an error occurs while checking the underlying
+ * stream.
+ */
+ @Override
+ public boolean ready() throws IOException
+ {
+ synchronized (lock)
+ {
+ return (pos < internalBuffer.length || internalReader.ready());
+ }
+ }
+
+ /**
+ * Closes the message for reading. This doesn't actually close the
+ * underlying stream. The underlying stream may still be used for
+ * communicating with the server and therefore is not closed.
+ * <p>
+ * If the end of the message has not yet been reached, this method
+ * will read the remainder of the message until it reaches the end,
+ * so that the underlying stream may continue to be used properly
+ * for communicating with the server. If you do not fully read
+ * a message, you MUST close it, otherwise your program will likely
+ * hang or behave improperly.
+ * @exception IOException If an error occurs while reading the
+ * underlying stream.
+ */
+ @Override
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (internalReader == null)
+ {
+ return;
+ }
+
+ if (!eof)
+ {
+ while (read() != -1)
+ {
+ ;
+ }
+ }
+ eof = true;
+ atBeginning = false;
+ pos = internalBuffer.length;
+ internalReader = null;
+ }
+ }
+}
diff --git a/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java b/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java
new file mode 100644
index 0000000..853e42f
--- /dev/null
+++ b/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java
@@ -0,0 +1,215 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/***
+ * DotTerminatedMessageWriter is a class used to write messages to a
+ * server that are terminated by a single dot followed by a
+ * &lt;CR&gt;&lt;LF&gt;
+ * sequence and with double dots appearing at the begining of lines which
+ * do not signal end of message yet start with a dot. Various Internet
+ * protocols such as NNTP and POP3 produce messages of this type.
+ * <p>
+ * This class handles the doubling of line-starting periods,
+ * converts single linefeeds to NETASCII newlines, and on closing
+ * will send the final message terminator dot and NETASCII newline
+ * sequence.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ ***/
+
+public final class DotTerminatedMessageWriter extends Writer
+{
+ private static final int __NOTHING_SPECIAL_STATE = 0;
+ private static final int __LAST_WAS_CR_STATE = 1;
+ private static final int __LAST_WAS_NL_STATE = 2;
+
+ private int __state;
+ private Writer __output;
+
+
+ /***
+ * Creates a DotTerminatedMessageWriter that wraps an existing Writer
+ * output destination.
+ * <p>
+ * @param output The Writer output destination to write the message.
+ ***/
+ public DotTerminatedMessageWriter(Writer output)
+ {
+ super(output);
+ __output = output;
+ __state = __NOTHING_SPECIAL_STATE;
+ }
+
+
+ /***
+ * Writes a character to the output. Note that a call to this method
+ * may result in multiple writes to the underling Writer in order to
+ * convert naked linefeeds to NETASCII line separators and to double
+ * line-leading periods. This is transparent to the programmer and
+ * is only mentioned for completeness.
+ * <p>
+ * @param ch The character to write.
+ * @exception IOException If an error occurs while writing to the
+ * underlying output.
+ ***/
+ @Override
+ public void write(int ch) throws IOException
+ {
+ synchronized (lock)
+ {
+ switch (ch)
+ {
+ case '\r':
+ __state = __LAST_WAS_CR_STATE;
+ __output.write('\r');
+ return ;
+ case '\n':
+ if (__state != __LAST_WAS_CR_STATE)
+ __output.write('\r');
+ __output.write('\n');
+ __state = __LAST_WAS_NL_STATE;
+ return ;
+ case '.':
+ // Double the dot at the beginning of a line
+ if (__state == __LAST_WAS_NL_STATE)
+ __output.write('.');
+ // Fall through
+ default:
+ __state = __NOTHING_SPECIAL_STATE;
+ __output.write(ch);
+ return ;
+ }
+ }
+ }
+
+
+ /***
+ * Writes a number of characters from a character array to the output
+ * starting from a given offset.
+ * <p>
+ * @param buffer The character array to write.
+ * @param offset The offset into the array at which to start copying data.
+ * @param length The number of characters to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * output.
+ ***/
+ @Override
+ public void write(char[] buffer, int offset, int length) throws IOException
+ {
+ synchronized (lock)
+ {
+ while (length-- > 0)
+ write(buffer[offset++]);
+ }
+ }
+
+
+ /***
+ * Writes a character array to the output.
+ * <p>
+ * @param buffer The character array to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * output.
+ ***/
+ @Override
+ public void write(char[] buffer) throws IOException
+ {
+ write(buffer, 0, buffer.length);
+ }
+
+
+ /***
+ * Writes a String to the output.
+ * <p>
+ * @param string The String to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * output.
+ ***/
+ @Override
+ public void write(String string) throws IOException
+ {
+ write(string.toCharArray());
+ }
+
+
+ /***
+ * Writes part of a String to the output starting from a given offset.
+ * <p>
+ * @param string The String to write.
+ * @param offset The offset into the String at which to start copying data.
+ * @param length The number of characters to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * output.
+ ***/
+ @Override
+ public void write(String string, int offset, int length) throws IOException
+ {
+ write(string.toCharArray(), offset, length);
+ }
+
+
+ /***
+ * Flushes the underlying output, writing all buffered output.
+ * <p>
+ * @exception IOException If an error occurs while writing to the underlying
+ * output.
+ ***/
+ @Override
+ public void flush() throws IOException
+ {
+ synchronized (lock)
+ {
+ __output.flush();
+ }
+ }
+
+
+ /***
+ * Flushes the underlying output, writing all buffered output, but doesn't
+ * actually close the underlying stream. The underlying stream may still
+ * be used for communicating with the server and therefore is not closed.
+ * <p>
+ * @exception IOException If an error occurs while writing to the underlying
+ * output or closing the Writer.
+ ***/
+ @Override
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (__output == null)
+ return ;
+
+ if (__state == __LAST_WAS_CR_STATE)
+ __output.write('\n');
+ else if (__state != __LAST_WAS_NL_STATE)
+ __output.write("\r\n");
+
+ __output.write(".\r\n");
+
+ __output.flush();
+ __output = null;
+ }
+ }
+
+}
diff --git a/src/org/apache/commons/net/io/FromNetASCIIInputStream.java b/src/org/apache/commons/net/io/FromNetASCIIInputStream.java
new file mode 100644
index 0000000..76588ab
--- /dev/null
+++ b/src/org/apache/commons/net/io/FromNetASCIIInputStream.java
@@ -0,0 +1,205 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+
+/***
+ * This class wraps an input stream, replacing all occurrences
+ * of &lt;CR&gt;&lt;LF&gt; (carriage return followed by a linefeed),
+ * which is the NETASCII standard for representing a newline, with the
+ * local line separator representation. You would use this class to
+ * implement ASCII file transfers requiring conversion from NETASCII.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ ***/
+
+public final class FromNetASCIIInputStream extends PushbackInputStream
+{
+ static final boolean _noConversionRequired;
+ static final String _lineSeparator;
+ static final byte[] _lineSeparatorBytes;
+
+ static {
+ _lineSeparator = System.getProperty("line.separator");
+ _noConversionRequired = _lineSeparator.equals("\r\n");
+ _lineSeparatorBytes = _lineSeparator.getBytes();
+ }
+
+ private int __length = 0;
+
+ /***
+ * Returns true if the NetASCII line separator differs from the system
+ * line separator, false if they are the same. This method is useful
+ * to determine whether or not you need to instantiate a
+ * FromNetASCIIInputStream object.
+ * <p>
+ * @return True if the NETASCII line separator differs from the local
+ * system line separator, false if they are the same.
+ ***/
+ public static final boolean isConversionRequired()
+ {
+ return !_noConversionRequired;
+ }
+
+ /***
+ * Creates a FromNetASCIIInputStream instance that wraps an existing
+ * InputStream.
+ ***/
+ public FromNetASCIIInputStream(InputStream input)
+ {
+ super(input, _lineSeparatorBytes.length + 1);
+ }
+
+
+ private int __read() throws IOException
+ {
+ int ch;
+
+ ch = super.read();
+
+ if (ch == '\r')
+ {
+ ch = super.read();
+ if (ch == '\n')
+ {
+ unread(_lineSeparatorBytes);
+ ch = super.read();
+ // This is a kluge for read(byte[], ...) to read the right amount
+ --__length;
+ }
+ else
+ {
+ if (ch != -1)
+ unread(ch);
+ return '\r';
+ }
+ }
+
+ return ch;
+ }
+
+
+ /***
+ * Reads and returns the next byte in the stream. If the end of the
+ * message has been reached, returns -1. Note that a call to this method
+ * may result in multiple reads from the underlying input stream in order
+ * to convert NETASCII line separators to the local line separator format.
+ * This is transparent to the programmer and is only mentioned for
+ * completeness.
+ * <p>
+ * @return The next character in the stream. Returns -1 if the end of the
+ * stream has been reached.
+ * @exception IOException If an error occurs while reading the underlying
+ * stream.
+ ***/
+ @Override
+ public int read() throws IOException
+ {
+ if (_noConversionRequired)
+ return super.read();
+
+ return __read();
+ }
+
+
+ /***
+ * Reads the next number of bytes from the stream into an array and
+ * returns the number of bytes read. Returns -1 if the end of the
+ * stream has been reached.
+ * <p>
+ * @param buffer The byte array in which to store the data.
+ * @return The number of bytes read. Returns -1 if the
+ * end of the message has been reached.
+ * @exception IOException If an error occurs in reading the underlying
+ * stream.
+ ***/
+ @Override
+ public int read(byte buffer[]) throws IOException
+ {
+ return read(buffer, 0, buffer.length);
+ }
+
+
+ /***
+ * Reads the next number of bytes from the stream into an array and returns
+ * the number of bytes read. Returns -1 if the end of the
+ * message has been reached. The characters are stored in the array
+ * starting from the given offset and up to the length specified.
+ * <p>
+ * @param buffer The byte array in which to store the data.
+ * @param offset The offset into the array at which to start storing data.
+ * @param length The number of bytes to read.
+ * @return The number of bytes read. Returns -1 if the
+ * end of the stream has been reached.
+ * @exception IOException If an error occurs while reading the underlying
+ * stream.
+ ***/
+ @Override
+ public int read(byte buffer[], int offset, int length) throws IOException
+ {
+ int ch, off;
+
+ if (length < 1)
+ return 0;
+
+ ch = available();
+
+ __length = (length > ch ? ch : length);
+
+ // If nothing is available, block to read only one character
+ if (__length < 1)
+ __length = 1;
+
+ if (_noConversionRequired)
+ return super.read(buffer, offset, __length);
+
+ if ((ch = __read()) == -1)
+ return -1;
+
+ off = offset;
+
+ do
+ {
+ buffer[offset++] = (byte)ch;
+ }
+ while (--__length > 0 && (ch = __read()) != -1);
+
+
+ return (offset - off);
+ }
+
+
+ // PushbackInputStream in JDK 1.1.3 returns the wrong thing
+ /***
+ * Returns the number of bytes that can be read without blocking EXCEPT
+ * when newline conversions have to be made somewhere within the
+ * available block of bytes. In other words, you really should not
+ * rely on the value returned by this method if you are trying to avoid
+ * blocking.
+ ***/
+ @Override
+ public int available() throws IOException
+ {
+ return (buf.length - pos) + in.available();
+ }
+
+}
diff --git a/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java b/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java
new file mode 100644
index 0000000..c025a1b
--- /dev/null
+++ b/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java
@@ -0,0 +1,174 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/***
+ * This class wraps an output stream, replacing all occurrences
+ * of &lt;CR&gt;&lt;LF&gt; (carriage return followed by a linefeed),
+ * which is the NETASCII standard for representing a newline, with the
+ * local line separator representation. You would use this class to
+ * implement ASCII file transfers requiring conversion from NETASCII.
+ * <p>
+ * Because of the translation process, a call to <code>flush()</code> will
+ * not flush the last byte written if that byte was a carriage
+ * return. A call to {@link #close close() }, however, will
+ * flush the carriage return.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ ***/
+
+public final class FromNetASCIIOutputStream extends FilterOutputStream
+{
+ private boolean __lastWasCR;
+
+ /***
+ * Creates a FromNetASCIIOutputStream instance that wraps an existing
+ * OutputStream.
+ * <p>
+ * @param output The OutputStream to wrap.
+ ***/
+ public FromNetASCIIOutputStream(OutputStream output)
+ {
+ super(output);
+ __lastWasCR = false;
+ }
+
+
+ private void __write(int ch) throws IOException
+ {
+ switch (ch)
+ {
+ case '\r':
+ __lastWasCR = true;
+ // Don't write anything. We need to see if next one is linefeed
+ break;
+ case '\n':
+ if (__lastWasCR)
+ {
+ out.write(FromNetASCIIInputStream._lineSeparatorBytes);
+ __lastWasCR = false;
+ break;
+ }
+ __lastWasCR = false;
+ out.write('\n');
+ break;
+ default:
+ if (__lastWasCR)
+ {
+ out.write('\r');
+ __lastWasCR = false;
+ }
+ out.write(ch);
+ break;
+ }
+ }
+
+
+ /***
+ * Writes a byte to the stream. Note that a call to this method
+ * might not actually write a byte to the underlying stream until a
+ * subsequent character is written, from which it can be determined if
+ * a NETASCII line separator was encountered.
+ * This is transparent to the programmer and is only mentioned for
+ * completeness.
+ * <p>
+ * @param ch The byte to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public synchronized void write(int ch)
+ throws IOException
+ {
+ if (FromNetASCIIInputStream._noConversionRequired)
+ {
+ out.write(ch);
+ return ;
+ }
+
+ __write(ch);
+ }
+
+
+ /***
+ * Writes a byte array to the stream.
+ * <p>
+ * @param buffer The byte array to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public synchronized void write(byte buffer[])
+ throws IOException
+ {
+ write(buffer, 0, buffer.length);
+ }
+
+
+ /***
+ * Writes a number of bytes from a byte array to the stream starting from
+ * a given offset.
+ * <p>
+ * @param buffer The byte array to write.
+ * @param offset The offset into the array at which to start copying data.
+ * @param length The number of bytes to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public synchronized void write(byte buffer[], int offset, int length)
+ throws IOException
+ {
+ if (FromNetASCIIInputStream._noConversionRequired)
+ {
+ // FilterOutputStream method is very slow.
+ //super.write(buffer, offset, length);
+ out.write(buffer, offset, length);
+ return ;
+ }
+
+ while (length-- > 0)
+ __write(buffer[offset++]);
+ }
+
+
+ /***
+ * Closes the stream, writing all pending data.
+ * <p>
+ * @exception IOException If an error occurs while closing the stream.
+ ***/
+ @Override
+ public synchronized void close()
+ throws IOException
+ {
+ if (FromNetASCIIInputStream._noConversionRequired)
+ {
+ super.close();
+ return ;
+ }
+
+ if (__lastWasCR)
+ out.write('\r');
+ super.close();
+ }
+}
diff --git a/src/org/apache/commons/net/io/SocketInputStream.java b/src/org/apache/commons/net/io/SocketInputStream.java
new file mode 100644
index 0000000..673f434
--- /dev/null
+++ b/src/org/apache/commons/net/io/SocketInputStream.java
@@ -0,0 +1,69 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+
+/***
+ * This class wraps an input stream, storing a reference to its originating
+ * socket. When the stream is closed, it will also close the socket
+ * immediately afterward. This class is useful for situations where you
+ * are dealing with a stream originating from a socket, but do not have
+ * a reference to the socket, and want to make sure it closes when the
+ * stream closes.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see SocketOutputStream
+ ***/
+
+public class SocketInputStream extends FilterInputStream
+{
+ private Socket __socket;
+
+ /***
+ * Creates a SocketInputStream instance wrapping an input stream and
+ * storing a reference to a socket that should be closed on closing
+ * the stream.
+ * <p>
+ * @param socket The socket to close on closing the stream.
+ * @param stream The input stream to wrap.
+ ***/
+ public SocketInputStream(Socket socket, InputStream stream)
+ {
+ super(stream);
+ __socket = socket;
+ }
+
+ /***
+ * Closes the stream and immediately afterward closes the referenced
+ * socket.
+ * <p>
+ * @exception IOException If there is an error in closing the stream
+ * or socket.
+ ***/
+ @Override
+ public void close() throws IOException
+ {
+ super.close();
+ __socket.close();
+ }
+}
diff --git a/src/org/apache/commons/net/io/SocketOutputStream.java b/src/org/apache/commons/net/io/SocketOutputStream.java
new file mode 100644
index 0000000..abd7f5d
--- /dev/null
+++ b/src/org/apache/commons/net/io/SocketOutputStream.java
@@ -0,0 +1,89 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/***
+ * This class wraps an output stream, storing a reference to its originating
+ * socket. When the stream is closed, it will also close the socket
+ * immediately afterward. This class is useful for situations where you
+ * are dealing with a stream originating from a socket, but do not have
+ * a reference to the socket, and want to make sure it closes when the
+ * stream closes.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see SocketInputStream
+ ***/
+
+public class SocketOutputStream extends FilterOutputStream
+{
+ private Socket __socket;
+
+ /***
+ * Creates a SocketOutputStream instance wrapping an output stream and
+ * storing a reference to a socket that should be closed on closing
+ * the stream.
+ * <p>
+ * @param socket The socket to close on closing the stream.
+ * @param stream The input stream to wrap.
+ ***/
+ public SocketOutputStream(Socket socket, OutputStream stream)
+ {
+ super(stream);
+ __socket = socket;
+ }
+
+
+ /***
+ * Writes a number of bytes from a byte array to the stream starting from
+ * a given offset. This method bypasses the equivalent method in
+ * FilterOutputStream because the FilterOutputStream implementation is
+ * very inefficient.
+ * <p>
+ * @param buffer The byte array to write.
+ * @param offset The offset into the array at which to start copying data.
+ * @param length The number of bytes to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public void write(byte buffer[], int offset, int length) throws IOException
+ {
+ out.write(buffer, offset, length);
+ }
+
+
+ /***
+ * Closes the stream and immediately afterward closes the referenced
+ * socket.
+ * <p>
+ * @exception IOException If there is an error in closing the stream
+ * or socket.
+ ***/
+ @Override
+ public void close() throws IOException
+ {
+ super.close();
+ __socket.close();
+ }
+}
diff --git a/src/org/apache/commons/net/io/ToNetASCIIInputStream.java b/src/org/apache/commons/net/io/ToNetASCIIInputStream.java
new file mode 100644
index 0000000..55e4735
--- /dev/null
+++ b/src/org/apache/commons/net/io/ToNetASCIIInputStream.java
@@ -0,0 +1,181 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/***
+ * This class wraps an input stream, replacing all singly occurring
+ * &lt;LF&gt; (linefeed) characters with &lt;CR&gt;&lt;LF&gt; (carriage return
+ * followed by linefeed), which is the NETASCII standard for representing
+ * a newline.
+ * You would use this class to implement ASCII file transfers requiring
+ * conversion to NETASCII.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ ***/
+
+public final class ToNetASCIIInputStream extends FilterInputStream
+{
+ private static final int __NOTHING_SPECIAL = 0;
+ private static final int __LAST_WAS_CR = 1;
+ private static final int __LAST_WAS_NL = 2;
+ private int __status;
+
+ /***
+ * Creates a ToNetASCIIInputStream instance that wraps an existing
+ * InputStream.
+ * <p>
+ * @param input The InputStream to .
+ ***/
+ public ToNetASCIIInputStream(InputStream input)
+ {
+ super(input);
+ __status = __NOTHING_SPECIAL;
+ }
+
+
+ /***
+ * Reads and returns the next byte in the stream. If the end of the
+ * message has been reached, returns -1.
+ * <p>
+ * @return The next character in the stream. Returns -1 if the end of the
+ * stream has been reached.
+ * @exception IOException If an error occurs while reading the underlying
+ * stream.
+ ***/
+ @Override
+ public int read() throws IOException
+ {
+ int ch;
+
+ if (__status == __LAST_WAS_NL)
+ {
+ __status = __NOTHING_SPECIAL;
+ return '\n';
+ }
+
+ ch = in.read();
+
+ switch (ch)
+ {
+ case '\r':
+ __status = __LAST_WAS_CR;
+ return '\r';
+ case '\n':
+ if (__status != __LAST_WAS_CR)
+ {
+ __status = __LAST_WAS_NL;
+ return '\r';
+ }
+ // else fall through
+ default:
+ __status = __NOTHING_SPECIAL;
+ return ch;
+ }
+ // statement not reached
+ //return ch;
+ }
+
+
+ /***
+ * Reads the next number of bytes from the stream into an array and
+ * returns the number of bytes read. Returns -1 if the end of the
+ * stream has been reached.
+ * <p>
+ * @param buffer The byte array in which to store the data.
+ * @return The number of bytes read. Returns -1 if the
+ * end of the message has been reached.
+ * @exception IOException If an error occurs in reading the underlying
+ * stream.
+ ***/
+ @Override
+ public int read(byte buffer[]) throws IOException
+ {
+ return read(buffer, 0, buffer.length);
+ }
+
+
+ /***
+ * Reads the next number of bytes from the stream into an array and returns
+ * the number of bytes read. Returns -1 if the end of the
+ * message has been reached. The characters are stored in the array
+ * starting from the given offset and up to the length specified.
+ * <p>
+ * @param buffer The byte array in which to store the data.
+ * @param offset The offset into the array at which to start storing data.
+ * @param length The number of bytes to read.
+ * @return The number of bytes read. Returns -1 if the
+ * end of the stream has been reached.
+ * @exception IOException If an error occurs while reading the underlying
+ * stream.
+ ***/
+ @Override
+ public int read(byte buffer[], int offset, int length) throws IOException
+ {
+ int ch, off;
+
+ if (length < 1)
+ return 0;
+
+ ch = available();
+
+ if (length > ch)
+ length = ch;
+
+ // If nothing is available, block to read only one character
+ if (length < 1)
+ length = 1;
+
+ if ((ch = read()) == -1)
+ return -1;
+
+ off = offset;
+
+ do
+ {
+ buffer[offset++] = (byte)ch;
+ }
+ while (--length > 0 && (ch = read()) != -1);
+
+ return (offset - off);
+ }
+
+ /*** Returns false. Mark is not supported. ***/
+ @Override
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ @Override
+ public int available() throws IOException
+ {
+ int result;
+
+ result = in.available();
+
+ if (__status == __LAST_WAS_NL)
+ return (result + 1);
+
+ return result;
+ }
+}
diff --git a/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java b/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java
new file mode 100644
index 0000000..aeacc98
--- /dev/null
+++ b/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java
@@ -0,0 +1,119 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/***
+ * This class wraps an output stream, replacing all singly occurring
+ * &lt;LF&gt; (linefeed) characters with &lt;CR&gt;&lt;LF&gt; (carriage return
+ * followed by linefeed), which is the NETASCII standard for representing
+ * a newline.
+ * You would use this class to implement ASCII file transfers requiring
+ * conversion to NETASCII.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ ***/
+
+public final class ToNetASCIIOutputStream extends FilterOutputStream
+{
+ private boolean __lastWasCR;
+
+ /***
+ * Creates a ToNetASCIIOutputStream instance that wraps an existing
+ * OutputStream.
+ * <p>
+ * @param output The OutputStream to wrap.
+ ***/
+ public ToNetASCIIOutputStream(OutputStream output)
+ {
+ super(output);
+ __lastWasCR = false;
+ }
+
+
+ /***
+ * Writes a byte to the stream. Note that a call to this method
+ * may result in multiple writes to the underlying input stream in order
+ * to convert naked newlines to NETASCII line separators.
+ * This is transparent to the programmer and is only mentioned for
+ * completeness.
+ * <p>
+ * @param ch The byte to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public synchronized void write(int ch)
+ throws IOException
+ {
+ switch (ch)
+ {
+ case '\r':
+ __lastWasCR = true;
+ out.write('\r');
+ return ;
+ case '\n':
+ if (!__lastWasCR)
+ out.write('\r');
+ // Fall through
+ default:
+ __lastWasCR = false;
+ out.write(ch);
+ return ;
+ }
+ }
+
+
+ /***
+ * Writes a byte array to the stream.
+ * <p>
+ * @param buffer The byte array to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public synchronized void write(byte buffer[])
+ throws IOException
+ {
+ write(buffer, 0, buffer.length);
+ }
+
+
+ /***
+ * Writes a number of bytes from a byte array to the stream starting from
+ * a given offset.
+ * <p>
+ * @param buffer The byte array to write.
+ * @param offset The offset into the array at which to start copying data.
+ * @param length The number of bytes to write.
+ * @exception IOException If an error occurs while writing to the underlying
+ * stream.
+ ***/
+ @Override
+ public synchronized void write(byte buffer[], int offset, int length)
+ throws IOException
+ {
+ while (length-- > 0)
+ write(buffer[offset++]);
+ }
+
+}
diff --git a/src/org/apache/commons/net/io/Util.java b/src/org/apache/commons/net/io/Util.java
new file mode 100644
index 0000000..4e85a93
--- /dev/null
+++ b/src/org/apache/commons/net/io/Util.java
@@ -0,0 +1,334 @@
+/*
+ * 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.commons.net.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
+/***
+ * The Util class cannot be instantiated and stores short static convenience
+ * methods that are often quite useful.
+ * <p>
+ * <p>
+ * @see CopyStreamException
+ * @see CopyStreamListener
+ * @see CopyStreamAdapter
+ * @author Daniel F. Savarese
+ ***/
+
+public final class Util
+{
+ /***
+ * The default buffer size used by {@link #copyStream copyStream }
+ * and {@link #copyReader copyReader }. It's value is 1024.
+ ***/
+ public static final int DEFAULT_COPY_BUFFER_SIZE = 1024;
+
+ // Cannot be instantiated
+ private Util()
+ { }
+
+
+ /***
+ * Copies the contents of an InputStream to an OutputStream using a
+ * copy buffer of a given size and notifies the provided
+ * CopyStreamListener of the progress of the copy operation by calling
+ * its bytesTransferred(long, int) method after each write to the
+ * destination. If you wish to notify more than one listener you should
+ * use a CopyStreamAdapter as the listener and register the additional
+ * listeners with the CopyStreamAdapter.
+ * <p>
+ * The contents of the InputStream are
+ * read until the end of the stream is reached, but neither the
+ * source nor the destination are closed. You must do this yourself
+ * outside of the method call. The number of bytes read/written is
+ * returned.
+ * <p>
+ * @param source The source InputStream.
+ * @param dest The destination OutputStream.
+ * @param bufferSize The number of bytes to buffer during the copy.
+ * @param streamSize The number of bytes in the stream being copied.
+ * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
+ * @param listener The CopyStreamListener to notify of progress. If
+ * this parameter is null, notification is not attempted.
+ * @param flush Whether to flush the output stream after every
+ * write. This is necessary for interactive sessions that rely on
+ * buffered streams. If you don't flush, the data will stay in
+ * the stream buffer.
+ * @exception CopyStreamException If an error occurs while reading from the
+ * source or writing to the destination. The CopyStreamException
+ * will contain the number of bytes confirmed to have been
+ * transferred before an
+ * IOException occurred, and it will also contain the IOException
+ * that caused the error. These values can be retrieved with
+ * the CopyStreamException getTotalBytesTransferred() and
+ * getIOException() methods.
+ ***/
+ public static final long copyStream(InputStream source, OutputStream dest,
+ int bufferSize, long streamSize,
+ CopyStreamListener listener,
+ boolean flush)
+ throws CopyStreamException
+ {
+ int bytes;
+ long total;
+ byte[] buffer;
+
+ buffer = new byte[bufferSize];
+ total = 0;
+
+ try
+ {
+ while ((bytes = source.read(buffer)) != -1)
+ {
+ // Technically, some read(byte[]) methods may return 0 and we cannot
+ // accept that as an indication of EOF.
+
+ if (bytes == 0)
+ {
+ bytes = source.read();
+ if (bytes < 0)
+ break;
+ dest.write(bytes);
+ if(flush)
+ dest.flush();
+ ++total;
+ if (listener != null)
+ listener.bytesTransferred(total, 1, streamSize);
+ continue;
+ }
+
+ dest.write(buffer, 0, bytes);
+ if(flush)
+ dest.flush();
+ total += bytes;
+ if (listener != null)
+ listener.bytesTransferred(total, bytes, streamSize);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CopyStreamException("IOException caught while copying.",
+ total, e);
+ }
+
+ return total;
+ }
+
+
+ /***
+ * Copies the contents of an InputStream to an OutputStream using a
+ * copy buffer of a given size and notifies the provided
+ * CopyStreamListener of the progress of the copy operation by calling
+ * its bytesTransferred(long, int) method after each write to the
+ * destination. If you wish to notify more than one listener you should
+ * use a CopyStreamAdapter as the listener and register the additional
+ * listeners with the CopyStreamAdapter.
+ * <p>
+ * The contents of the InputStream are
+ * read until the end of the stream is reached, but neither the
+ * source nor the destination are closed. You must do this yourself
+ * outside of the method call. The number of bytes read/written is
+ * returned.
+ * <p>
+ * @param source The source InputStream.
+ * @param dest The destination OutputStream.
+ * @param bufferSize The number of bytes to buffer during the copy.
+ * @param streamSize The number of bytes in the stream being copied.
+ * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
+ * @param listener The CopyStreamListener to notify of progress. If
+ * this parameter is null, notification is not attempted.
+ * @exception CopyStreamException If an error occurs while reading from the
+ * source or writing to the destination. The CopyStreamException
+ * will contain the number of bytes confirmed to have been
+ * transferred before an
+ * IOException occurred, and it will also contain the IOException
+ * that caused the error. These values can be retrieved with
+ * the CopyStreamException getTotalBytesTransferred() and
+ * getIOException() methods.
+ ***/
+ public static final long copyStream(InputStream source, OutputStream dest,
+ int bufferSize, long streamSize,
+ CopyStreamListener listener)
+ throws CopyStreamException
+ {
+ return copyStream(source, dest, bufferSize, streamSize, listener,
+ true);
+ }
+
+
+ /***
+ * Copies the contents of an InputStream to an OutputStream using a
+ * copy buffer of a given size. The contents of the InputStream are
+ * read until the end of the stream is reached, but neither the
+ * source nor the destination are closed. You must do this yourself
+ * outside of the method call. The number of bytes read/written is
+ * returned.
+ * <p>
+ * @param source The source InputStream.
+ * @param dest The destination OutputStream.
+ * @return The number of bytes read/written in the copy operation.
+ * @exception CopyStreamException If an error occurs while reading from the
+ * source or writing to the destination. The CopyStreamException
+ * will contain the number of bytes confirmed to have been
+ * transferred before an
+ * IOException occurred, and it will also contain the IOException
+ * that caused the error. These values can be retrieved with
+ * the CopyStreamException getTotalBytesTransferred() and
+ * getIOException() methods.
+ ***/
+ public static final long copyStream(InputStream source, OutputStream dest,
+ int bufferSize)
+ throws CopyStreamException
+ {
+ return copyStream(source, dest, bufferSize,
+ CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
+ }
+
+
+ /***
+ * Same as <code> copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
+ ***/
+ public static final long copyStream(InputStream source, OutputStream dest)
+ throws CopyStreamException
+ {
+ return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
+ }
+
+
+ /***
+ * Copies the contents of a Reader to a Writer using a
+ * copy buffer of a given size and notifies the provided
+ * CopyStreamListener of the progress of the copy operation by calling
+ * its bytesTransferred(long, int) method after each write to the
+ * destination. If you wish to notify more than one listener you should
+ * use a CopyStreamAdapter as the listener and register the additional
+ * listeners with the CopyStreamAdapter.
+ * <p>
+ * The contents of the Reader are
+ * read until its end is reached, but neither the source nor the
+ * destination are closed. You must do this yourself outside of the
+ * method call. The number of characters read/written is returned.
+ * <p>
+ * @param source The source Reader.
+ * @param dest The destination writer.
+ * @param bufferSize The number of characters to buffer during the copy.
+ * @param streamSize The number of characters in the stream being copied.
+ * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
+ * @param listener The CopyStreamListener to notify of progress. If
+ * this parameter is null, notification is not attempted.
+ * @return The number of characters read/written in the copy operation.
+ * @exception CopyStreamException If an error occurs while reading from the
+ * source or writing to the destination. The CopyStreamException
+ * will contain the number of bytes confirmed to have been
+ * transferred before an
+ * IOException occurred, and it will also contain the IOException
+ * that caused the error. These values can be retrieved with
+ * the CopyStreamException getTotalBytesTransferred() and
+ * getIOException() methods.
+ ***/
+ public static final long copyReader(Reader source, Writer dest,
+ int bufferSize, long streamSize,
+ CopyStreamListener listener)
+ throws CopyStreamException
+ {
+ int chars;
+ long total;
+ char[] buffer;
+
+ buffer = new char[bufferSize];
+ total = 0;
+
+ try
+ {
+ while ((chars = source.read(buffer)) != -1)
+ {
+ // Technically, some read(char[]) methods may return 0 and we cannot
+ // accept that as an indication of EOF.
+ if (chars == 0)
+ {
+ chars = source.read();
+ if (chars < 0)
+ break;
+ dest.write(chars);
+ dest.flush();
+ ++total;
+ if (listener != null)
+ listener.bytesTransferred(total, chars, streamSize);
+ continue;
+ }
+
+ dest.write(buffer, 0, chars);
+ dest.flush();
+ total += chars;
+ if (listener != null)
+ listener.bytesTransferred(total, chars, streamSize);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CopyStreamException("IOException caught while copying.",
+ total, e);
+ }
+
+ return total;
+ }
+
+
+ /***
+ * Copies the contents of a Reader to a Writer using a
+ * copy buffer of a given size. The contents of the Reader are
+ * read until its end is reached, but neither the source nor the
+ * destination are closed. You must do this yourself outside of the
+ * method call. The number of characters read/written is returned.
+ * <p>
+ * @param source The source Reader.
+ * @param dest The destination writer.
+ * @param bufferSize The number of characters to buffer during the copy.
+ * @return The number of characters read/written in the copy operation.
+ * @exception CopyStreamException If an error occurs while reading from the
+ * source or writing to the destination. The CopyStreamException
+ * will contain the number of bytes confirmed to have been
+ * transferred before an
+ * IOException occurred, and it will also contain the IOException
+ * that caused the error. These values can be retrieved with
+ * the CopyStreamException getTotalBytesTransferred() and
+ * getIOException() methods.
+ ***/
+ public static final long copyReader(Reader source, Writer dest,
+ int bufferSize)
+ throws CopyStreamException
+ {
+ return copyReader(source, dest, bufferSize,
+ CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
+ }
+
+
+ /***
+ * Same as <code> copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); </code>
+ ***/
+ public static final long copyReader(Reader source, Writer dest)
+ throws CopyStreamException
+ {
+ return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
+ }
+
+}