package aQute.lib.io;

import static java.util.Objects.requireNonNull;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

public class LimitedInputStream extends InputStream {
	private final InputStream	in;
	private int					remaining;
	private long				marked;

	public LimitedInputStream(InputStream in, int size) {
		this.in = requireNonNull(in);
		this.remaining = size;
		this.marked = size;
		if (size < 0) {
			throw new IllegalArgumentException("size must be non-negative");
		}
	}

	private void consume(int n) throws IOException {
		if (n - remaining > 0) {
			throw new EOFException("request to read more bytes than available");
		}
		remaining -= n;
	}

	private boolean hasRemaining() {
		return remaining > 0;
	}

	private int ranged(int n) {
		if (n <= 0) {
			return 0;
		}
		return Math.min(n, remaining);
	}

	private long ranged(long n) {
		if (n <= 0L) {
			return 0L;
		}
		return Math.min(n, remaining);
	}

	@Override
	public int read() throws IOException {
		if (hasRemaining()) {
			int read = in.read();
			consume(Byte.BYTES);
			return read;
		}
		eof();
		return -1;
	}

	@Override
	public int available() throws IOException {
		return ranged(in.available());
	}

	@Override
	public void close() throws IOException {
		remaining = 0;
		eof();
		in.close();
	}

	protected void eof() {}

	@Override
	public synchronized void mark(int readlimit) {
		in.mark((int) ranged(readlimit));
		marked = remaining;
	}

	@Override
	public boolean markSupported() {
		return in.markSupported();
	}

	@Override
	public int read(byte[] b, int off, int len) throws IOException {
		if (hasRemaining()) {
			int read = in.read(b, off, ranged(len));
			consume(read);
			return read;
		}
		eof();
		return -1;
	}

	@Override
	public int read(byte[] b) throws IOException {
		return read(b, 0, b.length);
	}

	@Override
	public synchronized void reset() throws IOException {
		if (!in.markSupported()) {
			throw new IOException("mark/reset not supported");
		}
		in.reset();
		remaining = marked;
	}

	@Override
	public long skip(long n) throws IOException {
		long skipped = in.skip(ranged(n));
		consume((int) skipped);
		return skipped;
	}
}

@@ -249,12 +249,12 @@
 ate 
-int%09
+long
 %09%09%09%09
@@ -540,19 +540,20 @@
 consume(
-int
+long
  n) thro
@@ -592,16 +592,17 @@
 ning %3E 0
+L
 ) %7B%0A%09%09%09t
@@ -755,107 +755,9 @@
  %3E 0
-;%0A%09%7D%0A%0A%09private int ranged(int n) %7B%0A%09%09if (n %3C= 0) %7B%0A%09%09%09return 0;%0A%09%09%7D%0A%09%09return Math.min(n, remaining)
+L
 ;%0A%09%7D
@@ -1095,16 +1095,22 @@
 %09%09return
+ (int)
  ranged(
@@ -1582,16 +1582,22 @@
 (b, off,
+ (int)
  ranged(
@@ -2049,16 +2049,16 @@
 ed(n));%0A
+
 %09%09consum
@@ -2059,22 +2059,16 @@
 consume(
-(int) 
 skipped)

Use long for internal remaining count in LimitedInputStream.