tikhomirov@51: /* tikhomirov@397: * Copyright (c) 2011-2012 TMate Software Ltd tikhomirov@157: * tikhomirov@157: * This program is free software; you can redistribute it and/or modify tikhomirov@157: * it under the terms of the GNU General Public License as published by tikhomirov@157: * the Free Software Foundation; version 2 of the License. tikhomirov@157: * tikhomirov@157: * This program is distributed in the hope that it will be useful, tikhomirov@157: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@157: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@157: * GNU General Public License for more details. tikhomirov@157: * tikhomirov@157: * For information on how to redistribute this software under tikhomirov@157: * the terms of a license other than GNU General Public License tikhomirov@157: * contact TMate Software at support@hg4j.com tikhomirov@51: */ tikhomirov@157: package org.tmatesoft.hg.internal; tikhomirov@51: tikhomirov@51: import java.io.IOException; tikhomirov@51: tikhomirov@157: tikhomirov@51: /** tikhomirov@51: * XXX Perhaps, DataAccessSlice? Unlike FilterInputStream, we limit amount of data read from DataAccess being filtered. tikhomirov@51: * tikhomirov@157: * tikhomirov@157: * @author Artem Tikhomirov tikhomirov@157: * @author TMate Software Ltd. tikhomirov@51: */ tikhomirov@51: public class FilterDataAccess extends DataAccess { tikhomirov@51: private final DataAccess dataAccess; tikhomirov@158: private final int offset; tikhomirov@51: private final int length; tikhomirov@51: private int count; tikhomirov@51: tikhomirov@158: public FilterDataAccess(DataAccess dataAccess, int 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@157: public FilterDataAccess reset() throws IOException { tikhomirov@51: count = length; tikhomirov@157: return this; 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@158: public int length() { tikhomirov@51: return length; tikhomirov@51: } tikhomirov@51: tikhomirov@51: @Override tikhomirov@158: public void seek(int 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@397: throw new IOException(String.format("Underflow. Bytes left: %d. FilterDA[offset: %d, length: %d]", count, offset, length)); 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@188: if (len == 0) { tikhomirov@188: return; tikhomirov@188: } tikhomirov@51: if (count <= 0 || len > count) { tikhomirov@397: throw new IOException(String.format("Underflow. Bytes left: %d, asked to read %d. FilterDA[offset: %d, length: %d]", count, len, offset, length)); 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: }