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 {
72 byte[] result = new byte[amount];
73 int has = size-byteIndex;
75 ReadableByteChannel c = channel;
76 ByteBuffer bb = byteBuffer;
77 System.arraycopy(bytes, byteIndex, result, 0, has);
78 ByteBuffer bb2 = ByteBuffer.wrap(result);
80 // For some peculiar reason this seems to avoid OOM with large blocks as compared to c.read(bb2
82 int todo = Math.min(amount-has, 65536);
84 int got = c.read(bb2);
85 if(got == -1) throw new IOException("Unexpected end-of-file");
87 // For some unknown reason this is needed!
88 // Spec indicates that read would increment position but it does not.
95 System.arraycopy(bytes, byteIndex, result, 0, amount);
103 final protected int getByte() throws IOException {
104 int has = size-byteIndex;
107 ReadableByteChannel c = channel;
108 ByteBuffer bb = byteBuffer;
111 throw new EOFException("Unexpected end-of-file");
118 result = bytes[byteIndex++] & 0xff;
122 public int getDynamicUInt32() throws IOException {
123 int length = getByte();
129 length += (getByte()<<3);
130 length += (getByte()<<11);
131 length += (getByte()<<19);
132 length += 0x10204080;
136 length += (getByte()<<4);
137 length += (getByte()<<12);
138 length += (getByte()<<20);
144 length += (getByte()<<5);
145 length += (getByte()<<13);
151 length += (getByte()<<6);
158 final protected int safeInt() throws IOException {
160 byte[] bytes = this.bytes;
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));
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);