/* * Copyright 2008 Federal Chancellery Austria and * Graz University of Technology * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.gv.egiz.smcc.util; import java.io.IOException; import java.io.InputStream; public abstract class TransparentFileInputStream extends InputStream { // private final int chunkSize = 256; private int chunkSize = 256; private byte[] buf = new byte[chunkSize]; private int start = 0; private int end = 0; private int offset = 0; private int length = -1; private int limit = -1; private int mark = -1; private int readlimit = -1; public TransparentFileInputStream() { } public TransparentFileInputStream(int length) { this.length = length; } public TransparentFileInputStream(int length, int chunkSize) { this.length = length; this.chunkSize = chunkSize; } public void setLimit(int limit) { this.limit = limit; } private int fill() throws IOException { if (start == end && (limit < 0 || offset < limit)) { int l; if (limit > 0 && limit - offset < chunkSize) { l = limit - offset; } else if (length > 0) { if (length - offset < chunkSize) { l = length - offset; } else { l = chunkSize - 1; } } else { l = chunkSize; } byte[] b = readBinary(offset, l); offset += b.length; if (mark < 0) { start = 0; end = b.length; System.arraycopy(b, 0, buf, start, b.length); } else { if (end - mark + b.length > buf.length) { // double buffer size byte[] nbuf = new byte[buf.length * 2]; System.arraycopy(buf, mark, nbuf, 0, end - mark); buf = nbuf; } else { System.arraycopy(buf, mark, buf, 0, end - mark); } start = start - mark; end = end - mark + b.length; mark = 0; System.arraycopy(b, 0, buf, start, b.length); } if (l > b.length) { // end of file reached setLimit(offset); } } return end - start; } protected abstract byte[] readBinary(int offset, int len) throws IOException; @Override public int read() throws IOException { int b = (fill() > 0) ? 0xFF & buf[start++] : -1; if (readlimit > 0 && start > readlimit) { mark = -1; readlimit = -1; } return b; } @Override public int read(byte[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int count = 0; int l; while (count < len) { if (fill() > 0) { l = Math.min(end - start, len - count); System.arraycopy(buf, start, b, off, l); start += l; off += l; count += l; if (readlimit > 0 && start > readlimit) { mark = -1; readlimit = -1; } } else { return (count > 0) ? count : -1; } } return count; } @Override public synchronized void mark(int readlimit) { this.readlimit = readlimit; mark = start; } @Override public boolean markSupported() { return true; } @Override public synchronized void reset() throws IOException { if (mark < 0) { throw new IOException(); } else { start = mark; } } @Override public long skip(long n) throws IOException { if (n <= 0) { return 0; } if (n <= end - start) { start += n; return n; } else { mark = -1; long remaining = n - (end - start); start = end; if (limit >= 0 && limit < offset + remaining) { remaining -= limit - offset; offset = limit; return n - remaining; } if (length >= 0 && length < offset + remaining) { remaining -= length - offset; offset = length; return n - remaining; } offset += remaining; return n; } } }