1 package org.simantics.graph.representation;
3 import java.io.Closeable;
4 import java.io.EOFException;
6 import java.io.FileInputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.nio.ByteBuffer;
10 import java.nio.channels.ReadableByteChannel;
13 * Must be closed after using by invoking {@link #close()}.
15 public class ByteFileReader implements Closeable {
17 final char[] chars = new char[3*128];
19 final private File file;
22 * May be <code>null</code>. If specified, it will be closed in
25 private InputStream stream;
28 * A readable channel must always be specified since it is used for all
29 * reading. Channel is never closed by this class.
31 private ReadableByteChannel channel;
33 final private ByteBuffer byteBuffer;
35 final protected byte[] bytes;
38 protected int byteIndex = 0;
40 final protected ReadableByteChannel getChannel() {
44 final protected ByteBuffer getByteBuffer() {
48 final protected byte[] getBytes() {
52 final protected String utf(byte[] bytes, int index, int target) {
54 while(index < target) {
55 int c = bytes[index++]&0xff;
57 chars[i++] = (char)(c&0x7F);
58 } else if (c > 0x07FF) {
59 int c2 = bytes[index++]&0xff;
60 int c3 = bytes[index++]&0xff;
61 chars[i++] = (char)(((c&0xf)<<12) + ((c2&0x3f)<<6) + (c3&0x3f));
63 int c2 = bytes[index++]&0xff;
64 chars[i++] = (char)(((c&0x1f)<<6) + (c2&0x3f));
68 return new String(chars, 0, i);
71 final protected byte[] safeBytes(int amount) throws IOException {
73 byte[] result = new byte[amount];
75 int has = size-byteIndex;
77 ReadableByteChannel c = channel;
78 ByteBuffer bb = byteBuffer;
79 System.arraycopy(bytes, byteIndex, result, 0, has);
80 ByteBuffer bb2 = ByteBuffer.wrap(result);
82 // For some peculiar reason this seems to avoid OOM with large blocks as compared to c.read(bb2
84 int todo = Math.min(amount-has, 65536);
86 int got = c.read(bb2);
87 if(got == -1) throw new IOException("Unexpected end-of-file");
94 System.arraycopy(bytes, byteIndex, result, 0, amount);
102 final protected int getByte() throws IOException {
103 int has = size-byteIndex;
106 ReadableByteChannel c = channel;
107 ByteBuffer bb = byteBuffer;
110 throw new EOFException("Unexpected end-of-file");
117 result = bytes[byteIndex];
124 public int getDynamicUInt32() throws IOException {
125 int length = getByte()&0xff;
131 length += ((getByte()&0xff)<<3);
132 length += ((getByte()&0xff)<<11);
133 length += ((getByte()&0xff)<<19);
134 length += 0x10204080;
138 length += ((getByte()&0xff)<<4);
139 length += ((getByte()&0xff)<<12);
140 length += ((getByte()&0xff)<<20);
146 length += ((getByte()&0xff)<<5);
147 length += ((getByte()&0xff)<<13);
153 length += ((getByte()&0xff)<<6);
160 final protected int safeInt() throws IOException {
162 if(byteIndex >= (size-5)) {
164 ReadableByteChannel c = channel;
165 ByteBuffer bb = byteBuffer;
166 if(byteIndex == size) {
168 if(size == -1) throw new EOFException("Unexpected end-of-file");
172 result |= ((int)(bytes[byteIndex++]&0xff)<<24);
173 if(byteIndex == size) {
175 if(size == -1) throw new EOFException("Unexpected end-of-file");
179 result |= ((int)(bytes[byteIndex++]&0xff)<<16);
180 if(byteIndex == size) {
182 if(size == -1) throw new EOFException("Unexpected end-of-file");
186 result |= ((int)(bytes[byteIndex++]&0xff)<<8);
187 if(byteIndex == size) {
189 if(size == -1) throw new EOFException("Unexpected end-of-file");
193 result |= ((int)(bytes[byteIndex++]&0xff)<<0);
194 if(byteIndex == size) {
201 return ((bytes[byteIndex++]&0xff)<<24) | ((bytes[byteIndex++]&0xff)<<16) | ((bytes[byteIndex++]&0xff)<<8) | ((bytes[byteIndex++]&0xff));
206 final protected int getSize() {
210 public ByteFileReader(File file, int size) throws IOException {
212 bytes = new byte[size];
213 byteBuffer = ByteBuffer.wrap(bytes);
217 FileInputStream fis = new FileInputStream(file);
219 channel = fis.getChannel();
220 this.size = channel.read(byteBuffer);
221 byteBuffer.position(0);
225 public ByteFileReader(FileInputStream stream, int size) throws IOException {
226 this(stream, stream.getChannel(), size);
229 public ByteFileReader(InputStream stream, ReadableByteChannel channel, int size) throws IOException {
231 bytes = new byte[size];
232 byteBuffer = ByteBuffer.wrap(bytes);
235 this.stream = stream;
236 this.channel = channel;
237 this.size = channel.read(byteBuffer);
238 byteBuffer.position(0);
242 public void close() throws IOException {
243 if (stream != null) {
249 public void reset() throws IOException {
251 if(file == null) throw new IllegalStateException("No file - cannot reset");
253 FileInputStream fis = new FileInputStream(file);
255 channel = fis.getChannel();
256 this.size = channel.read(byteBuffer);
257 byteBuffer.position(0);