tikhomirov@51: /* tikhomirov@51: * Copyright (c) 2011 Artem Tikhomirov tikhomirov@51: */ tikhomirov@51: package com.tmate.hgkit.fs; tikhomirov@51: tikhomirov@51: import java.io.IOException; tikhomirov@51: tikhomirov@51: /** tikhomirov@51: * XXX Perhaps, DataAccessSlice? Unlike FilterInputStream, we limit amount of data read from DataAccess being filtered. tikhomirov@51: * tikhomirov@51: * @author artem tikhomirov@51: */ tikhomirov@51: public class FilterDataAccess extends DataAccess { tikhomirov@51: private final DataAccess dataAccess; tikhomirov@51: private final long offset; tikhomirov@51: private final int length; tikhomirov@51: private int count; tikhomirov@51: tikhomirov@51: public FilterDataAccess(DataAccess dataAccess, long offset, int length) { tikhomirov@51: this.dataAccess = dataAccess; tikhomirov@51: this.offset = offset; tikhomirov@51: this.length = length; tikhomirov@51: count = length; tikhomirov@51: } tikhomirov@51: tikhomirov@51: protected int available() { tikhomirov@51: return count; tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public void reset() throws IOException { tikhomirov@51: count = length; tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public boolean isEmpty() { tikhomirov@51: return count <= 0; tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public long length() { tikhomirov@51: return length; tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public void seek(long localOffset) throws IOException { tikhomirov@51: if (localOffset < 0 || localOffset > length) { tikhomirov@51: throw new IllegalArgumentException(); tikhomirov@51: } tikhomirov@51: dataAccess.seek(offset + localOffset); tikhomirov@51: count = (int) (length - localOffset); tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public void skip(int bytes) throws IOException { tikhomirov@51: int newCount = count - bytes; tikhomirov@51: if (newCount < 0 || newCount > length) { tikhomirov@51: throw new IllegalArgumentException(); tikhomirov@51: } tikhomirov@51: seek(length - newCount); tikhomirov@51: /* tikhomirov@51: can't use next code because don't want to rewind backing DataAccess on reset() tikhomirov@51: i.e. this.reset() modifies state of this instance only, while filtered DA may go further. tikhomirov@51: Only actual this.skip/seek/read would rewind it to desired position tikhomirov@51: dataAccess.skip(bytes); tikhomirov@51: count = newCount; tikhomirov@51: */ tikhomirov@51: tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public byte readByte() throws IOException { tikhomirov@51: if (count <= 0) { tikhomirov@51: throw new IllegalArgumentException("Underflow"); // XXX be descriptive tikhomirov@51: } tikhomirov@51: if (count == length) { tikhomirov@51: dataAccess.seek(offset); tikhomirov@51: } tikhomirov@51: count--; tikhomirov@51: return dataAccess.readByte(); tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@51: public void readBytes(byte[] b, int off, int len) throws IOException { tikhomirov@51: if (count <= 0 || len > count) { tikhomirov@51: throw new IllegalArgumentException("Underflow"); // XXX be descriptive tikhomirov@51: } tikhomirov@51: if (count == length) { tikhomirov@51: dataAccess.seek(offset); tikhomirov@51: } tikhomirov@51: dataAccess.readBytes(b, off, len); tikhomirov@51: count -= len; tikhomirov@51: } tikhomirov@51: tikhomirov@51: // done shall be no-op, as we have no idea what's going on with DataAccess we filter tikhomirov@51: }