From 01c75a7aa09d0d9fd7a4c61f952aaa93972e7c99 Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 21:31:44 +0100 Subject: Reset eclipse workspace (commit hopefully changes nothing) --- .../apache/commons/net/io/CopyStreamAdapter.java | 122 ++++++++ src/org/apache/commons/net/io/CopyStreamEvent.java | 98 ++++++ .../apache/commons/net/io/CopyStreamException.java | 71 +++++ .../apache/commons/net/io/CopyStreamListener.java | 72 +++++ .../commons/net/io/DotTerminatedMessageReader.java | 280 +++++++++++++++++ .../commons/net/io/DotTerminatedMessageWriter.java | 215 +++++++++++++ .../commons/net/io/FromNetASCIIInputStream.java | 205 +++++++++++++ .../commons/net/io/FromNetASCIIOutputStream.java | 174 +++++++++++ .../apache/commons/net/io/SocketInputStream.java | 69 +++++ .../apache/commons/net/io/SocketOutputStream.java | 89 ++++++ .../commons/net/io/ToNetASCIIInputStream.java | 181 +++++++++++ .../commons/net/io/ToNetASCIIOutputStream.java | 119 ++++++++ src/org/apache/commons/net/io/Util.java | 334 +++++++++++++++++++++ 13 files changed, 2029 insertions(+) create mode 100644 src/org/apache/commons/net/io/CopyStreamAdapter.java create mode 100644 src/org/apache/commons/net/io/CopyStreamEvent.java create mode 100644 src/org/apache/commons/net/io/CopyStreamException.java create mode 100644 src/org/apache/commons/net/io/CopyStreamListener.java create mode 100644 src/org/apache/commons/net/io/DotTerminatedMessageReader.java create mode 100644 src/org/apache/commons/net/io/DotTerminatedMessageWriter.java create mode 100644 src/org/apache/commons/net/io/FromNetASCIIInputStream.java create mode 100644 src/org/apache/commons/net/io/FromNetASCIIOutputStream.java create mode 100644 src/org/apache/commons/net/io/SocketInputStream.java create mode 100644 src/org/apache/commons/net/io/SocketOutputStream.java create mode 100644 src/org/apache/commons/net/io/ToNetASCIIInputStream.java create mode 100644 src/org/apache/commons/net/io/ToNetASCIIOutputStream.java create mode 100644 src/org/apache/commons/net/io/Util.java (limited to 'src/org/apache/commons/net/io') 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. + *

+ *

+ * @see CopyStreamEvent + * @see CopyStreamListener + * @see Util + * @author Daniel F. Savarese + * @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. + *

+ *

+ * @see CopyStreamListener + * @see CopyStreamAdapter + * @see Util + * @author Daniel F. Savarese + * @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 UNKNOWN_STREAM_SIZE 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 UNKNOWN_STREAM_SIZE 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 Daniel F. Savarese + * @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. + *

+ *

+ * @see CopyStreamEvent + * @see CopyStreamAdapter + * @see Util + * @author Daniel F. Savarese + * @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 + * <CR><LF> + * 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. + *

+ * 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 Daniel F. Savarese + * @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. + *

+ * 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 + * <CR><LF> + * 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. + *

+ * 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. + *

+ *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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 <CR><LF> (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. + *

+ *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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 <CR><LF> (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. + *

+ * Because of the translation process, a call to flush() 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. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class FromNetASCIIOutputStream extends FilterOutputStream +{ + private boolean __lastWasCR; + + /*** + * Creates a FromNetASCIIOutputStream instance that wraps an existing + * OutputStream. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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 + * <LF> (linefeed) characters with <CR><LF> (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. + *

+ *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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 + * <LF> (linefeed) characters with <CR><LF> (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. + *

+ *

+ * @author Daniel F. Savarese + ***/ + +public final class ToNetASCIIOutputStream extends FilterOutputStream +{ + private boolean __lastWasCR; + + /*** + * Creates a ToNetASCIIOutputStream instance that wraps an existing + * OutputStream. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ * @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. + *

+ *

+ * @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. + *

+ * 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. + *

+ * @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. + *

+ * 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. + *

+ * @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. + *

+ * @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 copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); + ***/ + 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. + *

+ * 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. + *

+ * @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. + *

+ * @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 copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); + ***/ + public static final long copyReader(Reader source, Writer dest) + throws CopyStreamException + { + return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); + } + +} -- cgit v1.2.3