This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 aria.apache.commons.net.io;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
/**
|
||||
* CRLFLineReader implements a readLine() method that requires
|
||||
* exactly CRLF to terminate an input line.
|
||||
* This is required for IMAP, which allows bare CR and LF.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class CRLFLineReader extends BufferedReader {
|
||||
private static final char LF = '\n';
|
||||
private static final char CR = '\r';
|
||||
|
||||
/**
|
||||
* Creates a CRLFLineReader that wraps an existing Reader
|
||||
* input source.
|
||||
*
|
||||
* @param reader The Reader input source.
|
||||
*/
|
||||
public CRLFLineReader(Reader reader) {
|
||||
super(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a line of text.
|
||||
* A line is considered to be terminated by carriage return followed immediately by a linefeed.
|
||||
* This contrasts with BufferedReader which also allows other combinations.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
@Override public String readLine() throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int intch;
|
||||
boolean prevWasCR = false;
|
||||
synchronized (lock) { // make thread-safe (hopefully!)
|
||||
while ((intch = read()) != -1) {
|
||||
if (prevWasCR && intch == LF) {
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
if (intch == CR) {
|
||||
prevWasCR = true;
|
||||
} else {
|
||||
prevWasCR = false;
|
||||
}
|
||||
sb.append((char) intch);
|
||||
}
|
||||
}
|
||||
String string = sb.toString();
|
||||
if (string.length() == 0) { // immediate EOF
|
||||
return null;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 aria.apache.commons.net.io;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
import aria.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.
|
||||
*
|
||||
* @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $
|
||||
* @see CopyStreamEvent
|
||||
* @see CopyStreamListener
|
||||
* @see Util
|
||||
*/
|
||||
public class CopyStreamAdapter implements CopyStreamListener {
|
||||
private final 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.
|
||||
*/
|
||||
@Override public void bytesTransferred(CopyStreamEvent event) {
|
||||
for (EventListener listener : internalListeners) {
|
||||
((CopyStreamListener) (listener)).bytesTransferred(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. 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.
|
||||
*/
|
||||
@Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred,
|
||||
long streamSize) {
|
||||
for (EventListener listener : internalListeners) {
|
||||
((CopyStreamListener) (listener)).bytesTransferred(totalBytesTransferred, bytesTransferred,
|
||||
streamSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package aria.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.
|
||||
*
|
||||
* @version $Id: CopyStreamEvent.java 1652801 2015-01-18 17:10:05Z sebb $
|
||||
* @see CopyStreamListener
|
||||
* @see CopyStreamAdapter
|
||||
* @see Util
|
||||
*/
|
||||
public class CopyStreamEvent extends EventObject {
|
||||
private static final long serialVersionUID = -964927635655051867L;
|
||||
|
||||
/**
|
||||
* Constant used to indicate the stream size is unknown.
|
||||
*/
|
||||
public static final long UNKNOWN_STREAM_SIZE = -1;
|
||||
|
||||
private final int bytesTransferred;
|
||||
private final long totalBytesTransferred;
|
||||
private final 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return getClass().getName()
|
||||
+ "[source="
|
||||
+ source
|
||||
+ ", total="
|
||||
+ totalBytesTransferred
|
||||
+ ", bytes="
|
||||
+ bytesTransferred
|
||||
+ ", size="
|
||||
+ streamSize
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@@ -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 aria.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.
|
||||
*
|
||||
* @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $
|
||||
* @see Util
|
||||
*/
|
||||
public class CopyStreamException extends IOException {
|
||||
private static final long serialVersionUID = -2602899129433221532L;
|
||||
|
||||
private final long totalBytesTransferred;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
initCause(exception); // merge this into super() call once we need 1.6+
|
||||
totalBytesTransferred = bytesTransferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) getCause(); // cast is OK because it was initialised with an IOException
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 aria.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.
|
||||
*
|
||||
* @version $Id: CopyStreamListener.java 1652801 2015-01-18 17:10:05Z sebb $
|
||||
* @see CopyStreamEvent
|
||||
* @see CopyStreamAdapter
|
||||
* @see Util
|
||||
*/
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package aria.apache.commons.net.io;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
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, and ensures you cannot read past the end of the message.
|
||||
* <p>
|
||||
* Note: versions since 3.0 extend BufferedReader rather than Reader,
|
||||
* and no longer change the CRLF into the local EOL. Also only DOT CR LF
|
||||
* acts as EOF.
|
||||
*
|
||||
* @version $Id: DotTerminatedMessageReader.java 1747119 2016-06-07 02:22:24Z ggregory $
|
||||
*/
|
||||
public final class DotTerminatedMessageReader extends BufferedReader {
|
||||
private static final char LF = '\n';
|
||||
private static final char CR = '\r';
|
||||
private static final int DOT = '.';
|
||||
|
||||
private boolean atBeginning;
|
||||
private boolean eof;
|
||||
private boolean seenCR; // was last character CR?
|
||||
|
||||
/**
|
||||
* 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);
|
||||
// Assumes input is at start of message
|
||||
atBeginning = true;
|
||||
eof = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws IOException If an error occurs while reading the underlying
|
||||
* stream.
|
||||
*/
|
||||
@Override public int read() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (eof) {
|
||||
return -1; // Don't allow read past EOF
|
||||
}
|
||||
int chint = super.read();
|
||||
if (chint == -1) { // True EOF
|
||||
eof = true;
|
||||
return -1;
|
||||
}
|
||||
if (atBeginning) {
|
||||
atBeginning = false;
|
||||
if (chint == DOT) { // Have DOT
|
||||
mark(2); // need to check for CR LF or DOT
|
||||
chint = super.read();
|
||||
if (chint == -1) { // Should not happen
|
||||
// new Throwable("Trailing DOT").printStackTrace();
|
||||
eof = true;
|
||||
return DOT; // return the trailing DOT
|
||||
}
|
||||
if (chint == DOT) { // Have DOT DOT
|
||||
// no need to reset as we want to lose the first DOT
|
||||
return chint; // i.e. DOT
|
||||
}
|
||||
if (chint == CR) { // Have DOT CR
|
||||
chint = super.read();
|
||||
if (chint == -1) { // Still only DOT CR - should not happen
|
||||
//new Throwable("Trailing DOT CR").printStackTrace();
|
||||
reset(); // So CR is picked up next time
|
||||
return DOT; // return the trailing DOT
|
||||
}
|
||||
if (chint == LF) { // DOT CR LF
|
||||
atBeginning = true;
|
||||
eof = true;
|
||||
// Do we need to clear the mark somehow?
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Should not happen - lone DOT at beginning
|
||||
//new Throwable("Lone DOT followed by "+(char)chint).printStackTrace();
|
||||
reset();
|
||||
return DOT;
|
||||
} // have DOT
|
||||
} // atBeginning
|
||||
|
||||
// Handle CRLF in normal flow
|
||||
if (seenCR) {
|
||||
seenCR = false;
|
||||
if (chint == LF) {
|
||||
atBeginning = true;
|
||||
}
|
||||
}
|
||||
if (chint == CR) {
|
||||
seenCR = true;
|
||||
}
|
||||
return chint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws 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.
|
||||
* @throws IOException If an error occurs in reading the underlying
|
||||
* stream.
|
||||
*/
|
||||
@Override public int read(char[] buffer, int offset, int length) throws IOException {
|
||||
if (length < 1) {
|
||||
return 0;
|
||||
}
|
||||
int ch;
|
||||
synchronized (lock) {
|
||||
if ((ch = read()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int off = offset;
|
||||
|
||||
do {
|
||||
buffer[offset++] = (char) ch;
|
||||
} while (--length > 0 && (ch = read()) != -1);
|
||||
|
||||
return (offset - off);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @throws IOException If an error occurs while reading the
|
||||
* underlying stream.
|
||||
*/
|
||||
@Override public void close() throws IOException {
|
||||
synchronized (lock) {
|
||||
if (!eof) {
|
||||
while (read() != -1) {
|
||||
// read to EOF
|
||||
}
|
||||
}
|
||||
eof = true;
|
||||
atBeginning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a line of text.
|
||||
* A line is considered to be terminated by carriage return followed immediately by a linefeed.
|
||||
* This contrasts with BufferedReader which also allows other combinations.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
@Override public String readLine() throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int intch;
|
||||
synchronized (lock) { // make thread-safe (hopefully!)
|
||||
while ((intch = read()) != -1) {
|
||||
if (intch == LF && atBeginning) {
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
sb.append((char) intch);
|
||||
}
|
||||
}
|
||||
String string = sb.toString();
|
||||
if (string.length() == 0) { // immediate EOF
|
||||
return null;
|
||||
}
|
||||
// Should not happen - EOF without CRLF
|
||||
//new Throwable(string).printStackTrace();
|
||||
return string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 aria.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.
|
||||
*
|
||||
*
|
||||
***/
|
||||
|
||||
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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
*
|
||||
* @throws 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.
|
||||
*
|
||||
* @throws 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 aria.apache.commons.net.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/***
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
***/
|
||||
|
||||
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");
|
||||
try {
|
||||
_lineSeparatorBytes = _lineSeparator.getBytes("US-ASCII");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Broken JVM - cannot find US-ASCII charset!", e);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
* @param input the stream to wrap
|
||||
***/
|
||||
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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
* @throws IOException If an error occurs while reading the underlying
|
||||
* stream.
|
||||
***/
|
||||
@Override public int read(byte buffer[], int offset, int length) throws IOException {
|
||||
if (_noConversionRequired) {
|
||||
return super.read(buffer, offset, length);
|
||||
}
|
||||
|
||||
if (length < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ch, off;
|
||||
|
||||
ch = available();
|
||||
|
||||
__length = (length > ch ? ch : length);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// PushbackInputStream in JDK 1.1.3 returns the wrong thing
|
||||
// TODO - can we delete this override now?
|
||||
|
||||
/***
|
||||
* 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 {
|
||||
if (in == null) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
return (buf.length - pos) + in.available();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 aria.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.
|
||||
*
|
||||
*
|
||||
***/
|
||||
|
||||
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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
*
|
||||
* @throws 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package aria.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.
|
||||
*
|
||||
*
|
||||
* @see SocketOutputStream
|
||||
***/
|
||||
|
||||
public class SocketInputStream extends FilterInputStream {
|
||||
private final 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.
|
||||
*
|
||||
* @throws IOException If there is an error in closing the stream
|
||||
* or socket.
|
||||
***/
|
||||
@Override public void close() throws IOException {
|
||||
super.close();
|
||||
__socket.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 aria.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.
|
||||
*
|
||||
*
|
||||
* @see SocketInputStream
|
||||
***/
|
||||
|
||||
public class SocketOutputStream extends FilterOutputStream {
|
||||
private final 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.
|
||||
* @throws 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.
|
||||
*
|
||||
* @throws IOException If there is an error in closing the stream
|
||||
* or socket.
|
||||
***/
|
||||
@Override public void close() throws IOException {
|
||||
super.close();
|
||||
__socket.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 aria.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.
|
||||
*
|
||||
*
|
||||
***/
|
||||
|
||||
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 wrap.
|
||||
***/
|
||||
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.
|
||||
* @throws 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';
|
||||
}
|
||||
//$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.
|
||||
* @throws 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.
|
||||
* @throws 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 aria.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.
|
||||
*
|
||||
*
|
||||
***/
|
||||
|
||||
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.
|
||||
* @throws 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.
|
||||
* @throws 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.
|
||||
* @throws 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++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
351
AriaFtpPlug/src/main/java/aria/apache/commons/net/io/Util.java
Normal file
351
AriaFtpPlug/src/main/java/aria/apache/commons/net/io/Util.java
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* 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 aria.apache.commons.net.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.net.Socket;
|
||||
|
||||
/***
|
||||
* The Util class cannot be instantiated and stores short static convenience
|
||||
* methods that are often quite useful.
|
||||
*
|
||||
*
|
||||
* @see CopyStreamException
|
||||
* @see CopyStreamListener
|
||||
* @see CopyStreamAdapter
|
||||
***/
|
||||
|
||||
public final class Util {
|
||||
/**
|
||||
* The default buffer size ({@value}) used by
|
||||
* {@link #copyStream copyStream } and {@link #copyReader copyReader}
|
||||
* and by the copyReader/copyStream methods if a zero or negative buffer size is supplied.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param source The source InputStream.
|
||||
* @param dest The destination OutputStream.
|
||||
* @param bufferSize The number of bytes to buffer during the copy.
|
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
|
||||
* @param streamSize The number of bytes in the stream being copied.
|
||||
* Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
|
||||
* Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)}
|
||||
* @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.
|
||||
* @return number of bytes read/written
|
||||
* @throws 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 numBytes;
|
||||
long total = 0;
|
||||
byte[] buffer = new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE];
|
||||
|
||||
try {
|
||||
while (!Thread.currentThread().isInterrupted() && (numBytes = source.read(buffer)) != -1) {
|
||||
// Technically, some read(byte[]) methods may return 0 and we cannot
|
||||
// accept that as an indication of EOF.
|
||||
|
||||
if (numBytes == 0) {
|
||||
int singleByte = source.read();
|
||||
if (singleByte < 0) {
|
||||
break;
|
||||
}
|
||||
dest.write(singleByte);
|
||||
if (flush) {
|
||||
dest.flush();
|
||||
}
|
||||
++total;
|
||||
if (listener != null) {
|
||||
listener.bytesTransferred(total, 1, streamSize);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dest.write(buffer, 0, numBytes);
|
||||
if (flush) {
|
||||
dest.flush();
|
||||
}
|
||||
total += numBytes;
|
||||
if (listener != null) {
|
||||
listener.bytesTransferred(total, numBytes, 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.
|
||||
*
|
||||
* @param source The source InputStream.
|
||||
* @param dest The destination OutputStream.
|
||||
* @param bufferSize The number of bytes to buffer during the copy.
|
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
|
||||
* @param streamSize The number of bytes in the stream being copied.
|
||||
* Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
|
||||
* Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)}
|
||||
* @param listener The CopyStreamListener to notify of progress. If
|
||||
* this parameter is null, notification is not attempted.
|
||||
* @return number of bytes read/written
|
||||
* @throws 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.
|
||||
* @param bufferSize The number of bytes to buffer during the copy.
|
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
|
||||
* @return The number of bytes read/written in the copy operation.
|
||||
* @throws 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>
|
||||
* @param source where to copy from
|
||||
* @param dest where to copy to
|
||||
* @return number of bytes copied
|
||||
* @throws CopyStreamException on error
|
||||
***/
|
||||
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.
|
||||
*
|
||||
* @param source The source Reader.
|
||||
* @param dest The destination writer.
|
||||
* @param bufferSize The number of characters to buffer during the copy.
|
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
|
||||
* @param streamSize The number of characters in the stream being copied.
|
||||
* Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown.
|
||||
* Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)}
|
||||
* @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.
|
||||
* @throws 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 numChars;
|
||||
long total = 0;
|
||||
char[] buffer = new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE];
|
||||
|
||||
try {
|
||||
while ((numChars = source.read(buffer)) != -1) {
|
||||
// Technically, some read(char[]) methods may return 0 and we cannot
|
||||
// accept that as an indication of EOF.
|
||||
if (numChars == 0) {
|
||||
int singleChar = source.read();
|
||||
if (singleChar < 0) {
|
||||
break;
|
||||
}
|
||||
dest.write(singleChar);
|
||||
dest.flush();
|
||||
++total;
|
||||
if (listener != null) {
|
||||
listener.bytesTransferred(total, 1, streamSize);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dest.write(buffer, 0, numChars);
|
||||
dest.flush();
|
||||
total += numChars;
|
||||
if (listener != null) {
|
||||
listener.bytesTransferred(total, numChars, 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.
|
||||
* A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
|
||||
* @return The number of characters read/written in the copy operation.
|
||||
* @throws 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>
|
||||
* @param source where to copy from
|
||||
* @param dest where to copy to
|
||||
* @return number of bytes copied
|
||||
* @throws CopyStreamException on error
|
||||
***/
|
||||
public static final long copyReader(Reader source, Writer dest) throws CopyStreamException {
|
||||
return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the object quietly, catching rather than throwing IOException.
|
||||
* Intended for use from finally blocks.
|
||||
*
|
||||
* @param closeable the object to close, may be {@code null}
|
||||
* @since 3.0
|
||||
*/
|
||||
public static void closeQuietly(Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the socket quietly, catching rather than throwing IOException.
|
||||
* Intended for use from finally blocks.
|
||||
*
|
||||
* @param socket the socket to close, may be {@code null}
|
||||
* @since 3.0
|
||||
*/
|
||||
public static void closeQuietly(Socket socket) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility classes for IO support.
|
||||
*/
|
||||
package aria.apache.commons.net.io;
|
||||
Reference in New Issue
Block a user