From 063284837c8c366e5502b1b0264b8eb807b61732 Mon Sep 17 00:00:00 2001 From: Joe Robinson Date: Wed, 27 Oct 2010 14:21:09 +0100 Subject: Basic upload functionality to predifined location, with basic file browser --- .../commons/net/io/DotTerminatedMessageReader.java | 280 +++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 src/org/apache/commons/net/io/DotTerminatedMessageReader.java (limited to 'src/org/apache/commons/net/io/DotTerminatedMessageReader.java') 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; + } + } +} -- cgit v1.2.3