Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 9f1df30a33f90bd3d82bc9376187969c2f4eaac9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*******************************************************************************
 * 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();
	}

}

Back to the top