diff options
| author | Joe Robinson <joe@lc8n.com> | 2010-10-27 14:21:09 +0100 | 
|---|---|---|
| committer | Joe Robinson <joe@lc8n.com> | 2010-10-27 14:21:09 +0100 | 
| commit | 063284837c8c366e5502b1b0264b8eb807b61732 (patch) | |
| tree | fff3a1e1e5afaa671485b9d990704658276627ac /src/org/apache/commons/net/io | |
Basic upload functionality to predifined location, with basic file browser
Diffstat (limited to 'src/org/apache/commons/net/io')
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
 + * <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.
 + * <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
 + * <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.
 + * <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 <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.
 + * <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 <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.
 + * <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
 + * <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.
 + * <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
 + * <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.
 + * <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);
 +    }
 +
 +}
  | 
