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