javaerror-handlinginputstreamerror-recovery

Is this LimitedInputStream correct?


I've written a class called LimitedInputStream. It wraps around an existing input stream to limit the number of bytes read from it to a specified length. It's meant as an alternative to:

byte[] data = readAll(length);
InputStream ins = new ByteArrayInputStream(data);

Which requires the extra buffer.

This is the class:

public static class LimitedInputStream extends InputStream {
    private final InputStream ins;
    private int left;
    private int mark = -1;

    public LimitedInputStream(InputStream ins, int limit) {
        this.ins = ins;
        left = limit;
    }

    public void skipRest() throws IOException {
        ByteStreams.skipFully(ins, left);
        left = 0;
    }

    @Override
    public int read() throws IOException {
        if (left == 0) return -1;
        final int read = ins.read();
        if (read > 0) left--;
        return read;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if (left == 0) return -1;
        if (len > left) len = left;
        final int read = ins.read(b, off, len);
        if (read > 0) left -= read;
        return read;
    }

    @Override
    public int available() throws IOException {
        final int a = ins.available();
        return a > left ? left : a;
    }

    @Override
    public void mark(int readlimit) {
        ins.mark(readlimit);
        mark = left;
    }

    @Override
    public void reset() throws IOException {
        if (!ins.markSupported()) throw new IOException("Mark not supported");
        if (mark == -1) throw new IOException("Mark not set");

        ins.reset();
        left = mark;
    }

    @Override
    public long skip(long n) throws IOException {
        if (n > left) n = left;
        long skipped = ins.skip(n);
        left -= skipped;
        return skipped;
    }

}

Use case:

Object readObj() throws IOException {
    int len = readInt();
    final LimitedInputStream lis = new LimitedInputStream(this, len);
    try {
        return deserialize(new CompactInputStream(lis));
    } finally {
        lis.skipRest();
    }
}

for (something) {
  Object obj;
 try {
   obj = readObj();
 } catch (Exception e) {
   obj = null;
 }
 list.add(obj);
}

Could you code review my class for any serious bugs, e.g. possible mistakes in updating left?


Solution

  • Guava includes a LimitInputStream, so you may want to just use that.