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