kitaev@213: /* kitaev@213: * Copyright (c) 2011 TMate Software Ltd kitaev@213: * kitaev@213: * This program is free software; you can redistribute it and/or modify kitaev@213: * it under the terms of the GNU General Public License as published by kitaev@213: * the Free Software Foundation; version 2 of the License. kitaev@213: * kitaev@213: * This program is distributed in the hope that it will be useful, kitaev@213: * but WITHOUT ANY WARRANTY; without even the implied warranty of kitaev@213: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the kitaev@213: * GNU General Public License for more details. kitaev@213: * kitaev@213: * For information on how to redistribute this software under kitaev@213: * the terms of a license other than GNU General Public License kitaev@213: * contact TMate Software at support@hg4j.com kitaev@213: */ kitaev@213: package org.tmatesoft.hg.internal; kitaev@213: kitaev@213: import java.io.IOException; kitaev@213: kitaev@213: kitaev@213: /** kitaev@213: * XXX Perhaps, DataAccessSlice? Unlike FilterInputStream, we limit amount of data read from DataAccess being filtered. kitaev@213: * kitaev@213: * kitaev@213: * @author Artem Tikhomirov kitaev@213: * @author TMate Software Ltd. kitaev@213: */ kitaev@213: public class FilterDataAccess extends DataAccess { kitaev@213: private final DataAccess dataAccess; kitaev@213: private final int offset; kitaev@213: private final int length; kitaev@213: private int count; kitaev@213: kitaev@213: public FilterDataAccess(DataAccess dataAccess, int offset, int length) { kitaev@213: this.dataAccess = dataAccess; kitaev@213: this.offset = offset; kitaev@213: this.length = length; kitaev@213: count = length; kitaev@213: } kitaev@213: kitaev@213: protected int available() { kitaev@213: return count; kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public FilterDataAccess reset() throws IOException { kitaev@213: count = length; kitaev@213: return this; kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public boolean isEmpty() { kitaev@213: return count <= 0; kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public int length() { kitaev@213: return length; kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public void seek(int localOffset) throws IOException { kitaev@213: if (localOffset < 0 || localOffset > length) { kitaev@213: throw new IllegalArgumentException(); kitaev@213: } kitaev@213: dataAccess.seek(offset + localOffset); kitaev@213: count = (int) (length - localOffset); kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public void skip(int bytes) throws IOException { kitaev@213: int newCount = count - bytes; kitaev@213: if (newCount < 0 || newCount > length) { kitaev@213: throw new IllegalArgumentException(); kitaev@213: } kitaev@213: seek(length - newCount); kitaev@213: /* kitaev@213: can't use next code because don't want to rewind backing DataAccess on reset() kitaev@213: i.e. this.reset() modifies state of this instance only, while filtered DA may go further. kitaev@213: Only actual this.skip/seek/read would rewind it to desired position kitaev@213: dataAccess.skip(bytes); kitaev@213: count = newCount; kitaev@213: */ kitaev@213: kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public byte readByte() throws IOException { kitaev@213: if (count <= 0) { kitaev@213: throw new IllegalArgumentException("Underflow"); // XXX be descriptive kitaev@213: } kitaev@213: if (count == length) { kitaev@213: dataAccess.seek(offset); kitaev@213: } kitaev@213: count--; kitaev@213: return dataAccess.readByte(); kitaev@213: } kitaev@213: kitaev@213: @Override kitaev@213: public void readBytes(byte[] b, int off, int len) throws IOException { kitaev@213: if (len == 0) { kitaev@213: return; kitaev@213: } kitaev@213: if (count <= 0 || len > count) { kitaev@213: throw new IllegalArgumentException(String.format("Underflow. Bytes left: %d, asked to read %d", count, len)); kitaev@213: } kitaev@213: if (count == length) { kitaev@213: dataAccess.seek(offset); kitaev@213: } kitaev@213: dataAccess.readBytes(b, off, len); kitaev@213: count -= len; kitaev@213: } kitaev@213: kitaev@213: // done shall be no-op, as we have no idea what's going on with DataAccess we filter kitaev@213: }