/***************************************************************************** * Copyright (c) 2009 g-Eclipse Consortium * 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 * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Thomas Koeckerbauer MNM-Team, LMU Munich - initial API and implementation *****************************************************************************/ package eu.geclipse.traceview.internal; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; /** * This class is a buffered version of java.io.RandomAccessFile. * It is not a subclass of RandomAccessFile and it does not behave exactly like * RandomAccessFile. It only implements enough to make TraceFileCache happy. */ public class BufferedRandomAccessFile { private final static int BUFFER_SIZE = 64*1024; private final static int PRE_SEEK_BUFFER = 2*1024; private byte[] buffer = new byte[BUFFER_SIZE]; private boolean dirty = false; private long startOffset = 0; private int size = 0; private int bufferPos = 0; private RandomAccessFile file; public BufferedRandomAccessFile( File file, String mode ) throws FileNotFoundException { this.file = new RandomAccessFile( file, mode ); try { this.seek(0); } catch( IOException e ) { throw new FileNotFoundException( e.getMessage() ); } } public void write( int b ) throws IOException { if (this.bufferPos == BUFFER_SIZE) seek(this.startOffset + BUFFER_SIZE); this.buffer[this.bufferPos++] = (byte) b; if (this.size < this.bufferPos) this.size = this.bufferPos; this.dirty = true; } public int read() throws IOException { if (this.bufferPos == BUFFER_SIZE) seek(this.startOffset + BUFFER_SIZE); return this.buffer[this.bufferPos++]; } public void close() throws IOException { flush(); this.file.close(); } public void seek( long pos ) throws IOException { if ( pos < this.startOffset || pos >= this.startOffset + BUFFER_SIZE ) { // pos not in buffer flush(); this.startOffset = pos - PRE_SEEK_BUFFER; this.bufferPos = PRE_SEEK_BUFFER; if (this.startOffset < 0) { this.startOffset = 0; this.bufferPos = (int) pos; } if ( this.file.length() > this.startOffset ) { // startOffset inside of file this.file.seek( this.startOffset ); this.size = this.file.read( this.buffer ); } else { // startOffset outside of file this.size = 0; } } else { // pos in buffer this.bufferPos = (int) (pos - this.startOffset); } } public void readFully(byte[] b) throws IOException { flush(); this.file.seek( this.bufferPos + this.startOffset ); this.file.readFully(b); seek(this.bufferPos + this.startOffset + b.length); } public void flush() throws IOException { if ( this.dirty ) { this.file.seek( this.startOffset ); this.file.write( this.buffer, 0, this.size ); this.dirty = false; } } public FileChannel getChannel() throws IOException { flush(); return this.file.getChannel(); } public long length() throws IOException { return this.file.length(); } public int readInt() throws IOException { int a = this.read() & 0xff; int b = this.read() & 0xff; int c = this.read() & 0xff; int d = this.read() & 0xff; return ( a << 24 ) | ( b << 16 ) | ( c << 8 ) | d ; } public void writeInt( int value ) throws IOException { write( ( value >>> 24 ) & 0xFF ); write( ( value >>> 16 ) & 0xFF ); write( ( value >>> 8 ) & 0xFF ); write( value & 0xFF ); } }