/******************************************************************************* * Copyright (c) 2005, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.core.internal.registry; import java.io.*; /** * Provides buffered read from a java.io.RandomAccessFile. */ public class BufferedRandomInputStream extends InputStream { private RandomAccessFile inputFile; private String filePath; // Canonical path to the underlying file used for logging private int buffer_size; // Current size of the buffer private int buffer_pos; // Current read position in the buffer /** * The absolute position in the file where the buffered region starts. */ private long buffer_start = 0; /** * The current value of the RAF's file pointer. */ private long file_pointer; private byte buffer[]; public BufferedRandomInputStream(File file) throws IOException { this(file, 2048); // default buffer size } public BufferedRandomInputStream(File file, int bufferSize) throws IOException { filePath = file.getCanonicalPath(); inputFile = new RandomAccessFile(file, "r"); //$NON-NLS-1$ buffer = new byte[bufferSize]; file_pointer = 0; resetBuffer(); } private void resetBuffer() { buffer_pos = 0; buffer_size = 0; buffer_start = 0; } private int fillBuffer() throws IOException { buffer_pos = 0; buffer_start = file_pointer; buffer_size = inputFile.read(buffer, 0, buffer.length); file_pointer += buffer_size; return buffer_size; } public int read() throws IOException { if (buffer_pos >= buffer_size) { if (fillBuffer() <= 0) return -1; } return buffer[buffer_pos++] & 0xFF; } public int read(byte b[], int off, int len) throws IOException { int available = buffer_size - buffer_pos; if (available < 0) return -1; //the buffer contains all the bytes we need, so copy over and return if (len <= available) { System.arraycopy(buffer, buffer_pos, b, off, len); buffer_pos += len; return len; } // Use portion remaining in the buffer System.arraycopy(buffer, buffer_pos, b, off, available); if (fillBuffer() <= 0) return available; //recursive call to read again until we have the bytes we need return available + read(b, off + available, len - available); } public long skip(long n) throws IOException { if (n <= 0) return 0; int available = buffer_size - buffer_pos; if (n <= available) { buffer_pos += n; return n; } resetBuffer(); final int skipped = inputFile.skipBytes((int) (n - available)); file_pointer += skipped; return available + skipped; } public int available() { return (buffer_size - buffer_pos); } public void close() throws IOException { inputFile.close(); inputFile = null; buffer = null; } public String toString() { return filePath; } /** * Supplies functionality of the {@link java.io.RandomAccessFile#seek(long)} in * a buffer-friendly manner. * * @param pos offset * @throws IOException */ public void seek(long pos) throws IOException { if (pos >= buffer_start && pos < buffer_start + buffer_size) { //seeking within the current buffer buffer_pos = (int) (pos - buffer_start); } else { //seeking outside the buffer - just discard the buffer inputFile.seek(pos); file_pointer = pos; resetBuffer(); } } /** * Supplies functionality of the {@link java.io.RandomAccessFile#length()}. * @return file length * @throws IOException */ public long length() throws IOException { return inputFile.length(); } }