]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graph/src/org/simantics/graph/representation/ByteFileReader.java
Fixed various bugs in TG readers
[simantics/platform.git] / bundles / org.simantics.graph / src / org / simantics / graph / representation / ByteFileReader.java
1 package org.simantics.graph.representation;
2
3 import java.io.Closeable;
4 import java.io.EOFException;
5 import java.io.File;
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;
11
12 /**
13  * Must be closed after using by invoking {@link #close()}.
14  */
15 public class ByteFileReader implements Closeable {
16
17         final char[] chars = new char[3*128];
18
19         final private File file;
20         
21         /**
22          * May be <code>null</code>. If specified, it will be closed in
23          * {@link #close()}.
24          */
25         private InputStream stream;
26
27         /**
28          * A readable channel must always be specified since it is used for all
29          * reading. Channel is never closed by this class.
30          */
31         private ReadableByteChannel channel;
32         
33         final private ByteBuffer byteBuffer;
34         
35         final protected byte[] bytes;
36         private int size;
37
38         protected int byteIndex = 0;
39
40         final protected ReadableByteChannel getChannel() {
41                 return channel;
42         }
43         
44         final protected ByteBuffer getByteBuffer() {
45                 return byteBuffer;
46         }
47
48         final protected byte[] getBytes() {
49                 return bytes;
50
51         }
52         final protected String utf(byte[] bytes, int index, int target) {
53                 int i = 0;
54                 while(index < target) {
55                         int c = bytes[index++]&0xff;
56                         if(c <= 0x7F) {
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)); 
62                         } else {
63                                 int c2 = bytes[index++]&0xff;
64                                 chars[i++] = (char)(((c&0x1f)<<6) + (c2&0x3f)); 
65                         }
66                         
67                 }
68                 return new String(chars, 0, i);
69         }
70
71         final protected byte[] safeBytes(int amount) throws IOException {
72                 byte[] result = new byte[amount];
73                 int has = size-byteIndex;
74                 if(amount >= has) {
75                         ReadableByteChannel c = channel;
76                 ByteBuffer bb = byteBuffer;
77                         System.arraycopy(bytes, byteIndex, result, 0, has);
78                         ByteBuffer bb2 = ByteBuffer.wrap(result);
79                         bb2.position(has);
80                         // For some peculiar reason this seems to avoid OOM with large blocks as compared to c.read(bb2
81                         while(has < amount) {
82                                 int todo = Math.min(amount-has, 65536);
83                                 bb2.limit(has+todo);
84                                 int got = c.read(bb2);
85                                 if(got == -1) throw new IOException("Unexpected end-of-file");
86                                 has += got; 
87                                 // For some unknown reason this is needed!
88                                 // Spec indicates that read would increment position but it does not.
89                                 bb2.position(has);
90                         }
91                         size = c.read(bb);
92                         bb.position(0);
93                         byteIndex = 0;
94                 } else {
95                         System.arraycopy(bytes, byteIndex, result, 0, amount);
96                         byteIndex += amount;
97                 }
98
99                 return result;
100                 
101         }
102
103         final protected int getByte() throws IOException {
104             int has = size-byteIndex;
105             int result;
106         if(has == 0) {
107             ReadableByteChannel c = channel;
108             ByteBuffer bb = byteBuffer;
109             size = c.read(bb);
110             if(size == -1) {
111                                 throw new EOFException("Unexpected end-of-file");
112             }
113             bb.position(0);
114             byteIndex = 0;
115             if(size == 0)
116                 return -1;
117         }
118         result = bytes[byteIndex++] & 0xff;
119         return result;
120         }
121
122         public int getDynamicUInt32() throws IOException {
123                 int length = getByte(); 
124                 if(length >= 0x80) {
125                         if(length >= 0xc0) {
126                                 if(length >= 0xe0) {
127                                         if(length >= 0xf0) {
128                                                 length &= 0x0f;
129                                                 length += (getByte()<<3);
130                                                 length += (getByte()<<11);
131                                                 length += (getByte()<<19);
132                                                 length += 0x10204080;
133                                         }
134                                         else {
135                                                 length &= 0x1f;
136                                                 length += (getByte()<<4);
137                                                 length += (getByte()<<12);
138                                                 length += (getByte()<<20);
139                                                 length += 0x204080;
140                                         }
141                                 }
142                                 else {
143                                         length &= 0x3f;
144                                         length += (getByte()<<5);
145                                         length += (getByte()<<13);
146                                         length += 0x4080;
147                                 }
148                         }
149                         else {
150                                 length &= 0x7f;
151                                 length += (getByte()<<6);
152                                 length += 0x80;
153                         }
154                 }
155                 return length;
156         }
157
158         final protected int safeInt() throws IOException {
159
160                 byte[] bytes = this.bytes;
161
162                 if(byteIndex >= (size-5)) {
163                         int result = 0;
164                         ReadableByteChannel c = channel;
165                         ByteBuffer bb = byteBuffer;
166                         if(byteIndex == size) {
167                                 size = c.read(bb);
168                                 if(size == -1) throw new EOFException("Unexpected end-of-file");
169                                 bb.position(0);
170                                 byteIndex = 0;
171                         }
172                         result |= ((int)(bytes[byteIndex++]&0xff)<<24);
173                         if(byteIndex == size) {
174                                 size = c.read(bb);
175                                 if(size == -1) throw new EOFException("Unexpected end-of-file");
176                                 bb.position(0);
177                                 byteIndex = 0;
178                         }
179                         result |= ((int)(bytes[byteIndex++]&0xff)<<16);
180                         if(byteIndex == size) {
181                                 size = c.read(bb);
182                                 if(size == -1) throw new EOFException("Unexpected end-of-file");
183                                 bb.position(0);
184                                 byteIndex = 0;
185                         }
186                         result |= ((int)(bytes[byteIndex++]&0xff)<<8);
187                         if(byteIndex == size) {
188                                 size = c.read(bb);
189                                 if(size == -1) throw new EOFException("Unexpected end-of-file");
190                                 bb.position(0);
191                                 byteIndex = 0;
192                         }
193                         result |= ((int)(bytes[byteIndex++]&0xff));
194                         if(byteIndex == size) {
195                                 size = c.read(bb);
196                                 bb.position(0);
197                                 byteIndex = 0;
198                         }
199                         return result;
200                 } else {
201                         return ((bytes[byteIndex++]&0xff)<<24) | ((bytes[byteIndex++]&0xff)<<16) | ((bytes[byteIndex++]&0xff)<<8) | ((bytes[byteIndex++]&0xff));
202                 }
203
204         }
205
206         final protected int getSize() {
207                 return size;
208         }
209
210         public ByteFileReader(File file, int size) throws IOException {
211             
212         bytes = new byte[size];
213         byteBuffer = ByteBuffer.wrap(bytes);
214
215         this.file = file;
216         
217         FileInputStream fis = new FileInputStream(file); 
218         stream = fis; 
219         channel = fis.getChannel();
220         this.size = channel.read(byteBuffer);
221         byteBuffer.position(0);
222             
223         }
224
225         public ByteFileReader(FileInputStream stream, int size) throws IOException {
226                 this(stream, stream.getChannel(), size);
227         }
228     
229         public ByteFileReader(InputStream stream, ReadableByteChannel channel, int size) throws IOException {
230             
231                 bytes = new byte[size];
232                 byteBuffer = ByteBuffer.wrap(bytes);
233
234                 this.file = null;
235                 this.stream = stream;
236                 this.channel = channel;
237                 this.size = channel.read(byteBuffer);
238                 byteBuffer.position(0);
239                 
240         }
241
242         public void close() throws IOException {
243                 if (stream != null) {
244                         stream.close();
245                         stream = null;
246                 }
247         }
248         
249         public void reset() throws IOException {
250             
251             if(file == null) throw new IllegalStateException("No file - cannot reset");
252         
253         FileInputStream fis = new FileInputStream(file); 
254         stream = fis; 
255         channel = fis.getChannel();
256         this.size = channel.read(byteBuffer);
257         byteBuffer.position(0);
258         
259         }
260
261 }