blob: 5cafd304782440d9df5b0b6e096e4a73ebf6e960 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* IBM - Initial implementation
******************************************************************************/
package org.eclipse.team.internal.ccvs.core.streams;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import org.eclipse.core.runtime.OperationCanceledException;
/**
* Simulates a stream that represents only a portion of the underlying stream.
* Will report EOF when this portion has been fully read and prevent further reads.
* The underlying stream is not closed on close(), but the remaining unread input
* may optionally be skip()'d.
*
* Supports resuming partially completed operations after an InterruptedIOException
* if the underlying stream does. Check the bytesTransferred field to determine how
* much of the operation completed; conversely, at what point to resume.
*/
public class SizeConstrainedInputStream extends FilterInputStream {
private boolean discardOnClose;
private long bytesRemaining;
/**
* Creates a size contrained input stream.
* @param in the underlying input stream, never actually closed by this filter
* @param size the maximum number of bytes of the underlying input stream that
* can be read through this filter
* @param discardOnClose if true, discards remaining unread bytes on close()
*/
public SizeConstrainedInputStream(InputStream in, long size, boolean discardOnClose) {
super(in);
this.bytesRemaining = size;
this.discardOnClose = discardOnClose;
}
/**
* Prevents further reading from the stream but does not close the underlying stream.
* If discardOnClose, skip()'s over any remaining unread bytes in the constrained region.
* @throws IOException if an i/o error occurs
*/
public void close() throws IOException {
try {
if (discardOnClose) {
while (bytesRemaining != 0 && skip(bytesRemaining) != 0);
}
} catch (OperationCanceledException e) {
// The receiver is likely wrapping a PollingInputStream which could throw
// an OperationCanceledException on a skip.
// Since we're closing, just ignore the cancel and let the caller check the monitor
} finally {
bytesRemaining = 0;
}
}
/**
* Wraps the underlying stream's method.
* Simulates an end-of-file condition if the end of the constrained region has been reached.
* @throws IOException if an i/o error occurs
*/
public int available() throws IOException {
int amount = in.available();
if (amount > bytesRemaining) amount = (int) bytesRemaining;
return amount;
}
/**
* Wraps the underlying stream's method.
* Simulates an end-of-file condition if the end of the constrained region has been reached.
* @throws InterruptedIOException if the operation was interrupted before all of the
* bytes specified have been skipped, bytesTransferred will be zero
* @throws IOException if an i/o error occurs
*/
public int read() throws IOException {
if (bytesRemaining == 0) return -1;
int b = in.read();
if (b != -1) bytesRemaining -= 1;
return b;
}
/**
* Wraps the underlying stream's method.
* Simulates an end-of-file condition if the end of the constrained region has been reached.
* @throws InterruptedIOException if the operation was interrupted before all of the
* bytes specified have been skipped, bytesTransferred may be non-zero
* @throws IOException if an i/o error occurs
*/
public int read(byte[] buffer, int offset, int length) throws IOException {
if (length > bytesRemaining) {
if (bytesRemaining == 0) return -1;
length = (int) bytesRemaining;
}
try {
int count = in.read(buffer, offset, length);
if (count != -1) bytesRemaining -= count;
return count;
} catch (InterruptedIOException e) {
bytesRemaining -= e.bytesTransferred;
throw e;
}
}
/**
* Wraps the underlying stream's method.
* Simulates an end-of-file condition if the end of the constrained region has been reached.
* @throws InterruptedIOException if the operation was interrupted before all of the
* bytes specified have been skipped, bytesTransferred may be non-zero
* @throws IOException if an i/o error occurs
*/
public long skip(long amount) throws IOException {
if (amount > bytesRemaining) amount = bytesRemaining;
try {
long count = in.skip(amount);
bytesRemaining -= count;
return count;
} catch (InterruptedIOException e) {
bytesRemaining -= e.bytesTransferred;
throw e;
}
}
/**
* Mark is not supported by the wrapper even if the underlying stream does, returns false.
*/
public boolean markSupported() {
return false;
}
}