1 |
using System; |
2 |
using System.Collections.Generic; |
3 |
using System.IO; |
4 |
using System.Text; |
5 |
using Oni.Imaging; |
6 |
|
7 |
namespace Oni |
8 |
{ |
9 |
internal sealed class BinaryReader : IDisposable |
10 |
{ |
11 |
#region Private data |
12 |
private static readonly byte[] seekBuffer = new byte[512]; |
13 |
private static readonly Encoding encoding = Encoding.UTF8; |
14 |
private const float rotationAngleScale = MathHelper.Pi / 32767.5f; |
15 |
|
16 |
private FileStream stream; |
17 |
private byte[] buffer; |
18 |
private bool bigEndian; |
19 |
private InstanceFile instanceFile; |
20 |
#endregion |
21 |
|
22 |
public BinaryReader(string filePath) |
23 |
{ |
24 |
this.buffer = new byte[8]; |
25 |
this.stream = File.OpenRead(filePath); |
26 |
} |
27 |
|
28 |
public BinaryReader(string filePath, bool bigEndian) |
29 |
: this(filePath) |
30 |
{ |
31 |
this.bigEndian = bigEndian; |
32 |
} |
33 |
|
34 |
public BinaryReader(string filePath, InstanceFile instanceFile) |
35 |
: this(filePath) |
36 |
{ |
37 |
this.instanceFile = instanceFile; |
38 |
} |
39 |
|
40 |
public void Dispose() |
41 |
{ |
42 |
if (stream != null) |
43 |
stream.Dispose(); |
44 |
|
45 |
stream = null; |
46 |
buffer = null; |
47 |
} |
48 |
|
49 |
public string Name => stream.Name; |
50 |
|
51 |
public int Length => (int)stream.Length; |
52 |
|
53 |
public int Position |
54 |
{ |
55 |
get |
56 |
{ |
57 |
return (int)stream.Position; |
58 |
} |
59 |
set |
60 |
{ |
61 |
int currentPosition = (int)stream.Position; |
62 |
int delta = value - currentPosition; |
63 |
|
64 |
if (delta == 0) |
65 |
return; |
66 |
|
67 |
if (delta > 0 && delta <= seekBuffer.Length) |
68 |
stream.Read(seekBuffer, 0, delta); |
69 |
else |
70 |
stream.Position = value; |
71 |
} |
72 |
} |
73 |
|
74 |
public void Skip(int length) |
75 |
{ |
76 |
Position += length; |
77 |
} |
78 |
|
79 |
public void SkipCString() |
80 |
{ |
81 |
for (int b = 1; b != 0 && b != -1; b = stream.ReadByte()) |
82 |
; |
83 |
} |
84 |
|
85 |
public int Read(byte[] buffer, int offset, int length) |
86 |
{ |
87 |
return stream.Read(buffer, offset, length); |
88 |
} |
89 |
|
90 |
public byte[] ReadBytes(int length) |
91 |
{ |
92 |
var buffer = new byte[length]; |
93 |
int offset = 0; |
94 |
|
95 |
while (length > 0) |
96 |
{ |
97 |
int read = stream.Read(buffer, offset, length); |
98 |
|
99 |
if (read == 0) |
100 |
break; |
101 |
|
102 |
offset += read; |
103 |
length -= read; |
104 |
} |
105 |
|
106 |
if (offset != buffer.Length) |
107 |
{ |
108 |
var result = new byte[offset]; |
109 |
Buffer.BlockCopy(buffer, 0, result, 0, offset); |
110 |
buffer = result; |
111 |
} |
112 |
|
113 |
return buffer; |
114 |
} |
115 |
|
116 |
public byte ReadByte() |
117 |
{ |
118 |
int value = stream.ReadByte(); |
119 |
|
120 |
if (value == -1) |
121 |
throw new EndOfStreamException(); |
122 |
|
123 |
return (byte)value; |
124 |
} |
125 |
|
126 |
public bool ReadBoolean() |
127 |
{ |
128 |
return (ReadByte() != 0); |
129 |
} |
130 |
|
131 |
public ushort ReadUInt16() |
132 |
{ |
133 |
FillBuffer(2); |
134 |
|
135 |
if (bigEndian) |
136 |
{ |
137 |
return (ushort)(buffer[1] | buffer[0] << 8); |
138 |
} |
139 |
|
140 |
return (ushort)(buffer[0] | buffer[1] << 8); |
141 |
} |
142 |
|
143 |
public ushort[] ReadUInt16Array(int length) |
144 |
{ |
145 |
var array = new ushort[length]; |
146 |
|
147 |
for (int i = 0; i < array.Length; i++) |
148 |
array[i] = ReadUInt16(); |
149 |
|
150 |
return array; |
151 |
} |
152 |
|
153 |
public uint ReadUInt32() |
154 |
{ |
155 |
FillBuffer(4); |
156 |
|
157 |
if (bigEndian) |
158 |
{ |
159 |
return (uint)(buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24); |
160 |
} |
161 |
|
162 |
return (uint)(buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24); |
163 |
} |
164 |
|
165 |
public ulong ReadUInt64() |
166 |
{ |
167 |
FillBuffer(8); |
168 |
|
169 |
ulong lo, hi; |
170 |
|
171 |
if (bigEndian) |
172 |
{ |
173 |
hi = (uint)(buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24); |
174 |
lo = (uint)(buffer[7] | buffer[6] << 8 | buffer[5] << 16 | buffer[4] << 24); |
175 |
} |
176 |
else |
177 |
{ |
178 |
lo = (uint)(buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24); |
179 |
hi = (uint)(buffer[4] | buffer[5] << 8 | buffer[6] << 16 | buffer[7] << 24); |
180 |
} |
181 |
|
182 |
return (hi << 32) | lo; |
183 |
} |
184 |
|
185 |
public short ReadInt16() |
186 |
{ |
187 |
return (short)ReadUInt16(); |
188 |
} |
189 |
|
190 |
public short[] ReadInt16Array(int length) |
191 |
{ |
192 |
var array = new short[length]; |
193 |
|
194 |
for (int i = 0; i < array.Length; i++) |
195 |
array[i] = ReadInt16(); |
196 |
|
197 |
return array; |
198 |
} |
199 |
|
200 |
public int ReadInt32() |
201 |
{ |
202 |
return (int)ReadUInt32(); |
203 |
} |
204 |
|
205 |
public int[] ReadInt32VarArray() |
206 |
{ |
207 |
return ReadInt32Array(ReadInt32()); |
208 |
} |
209 |
|
210 |
public int[] ReadInt32Array(int length) |
211 |
{ |
212 |
var array = new int[length]; |
213 |
|
214 |
for (int i = 0; i < array.Length; i++) |
215 |
array[i] = ReadInt32(); |
216 |
|
217 |
return array; |
218 |
} |
219 |
|
220 |
public long ReadInt64() |
221 |
{ |
222 |
return (long)ReadUInt64(); |
223 |
} |
224 |
|
225 |
public unsafe float ReadSingle() |
226 |
{ |
227 |
uint value = ReadUInt32(); |
228 |
return *((float*)&value); |
229 |
} |
230 |
|
231 |
public float[] ReadSingleArray(int length) |
232 |
{ |
233 |
var data = new float[length]; |
234 |
|
235 |
for (int i = 0; i < data.Length; i++) |
236 |
data[i] = ReadSingle(); |
237 |
|
238 |
return data; |
239 |
} |
240 |
|
241 |
public unsafe double ReadDouble() |
242 |
{ |
243 |
ulong value = ReadUInt64(); |
244 |
return *((double*)&value); |
245 |
} |
246 |
|
247 |
public Vector2 ReadVector2() |
248 |
{ |
249 |
return new Vector2(ReadSingle(), ReadSingle()); |
250 |
} |
251 |
|
252 |
public Vector2[] ReadVector2VarArray() |
253 |
{ |
254 |
return ReadVector2Array(ReadInt32()); |
255 |
} |
256 |
|
257 |
public Vector2[] ReadVector2Array(int length) |
258 |
{ |
259 |
var data = new Vector2[length]; |
260 |
|
261 |
for (int i = 0; i < data.Length; i++) |
262 |
data[i] = ReadVector2(); |
263 |
|
264 |
return data; |
265 |
} |
266 |
|
267 |
public Vector3 ReadVector3() |
268 |
{ |
269 |
return new Vector3(ReadSingle(), ReadSingle(), ReadSingle()); |
270 |
} |
271 |
|
272 |
public Vector3[] ReadVector3VarArray() |
273 |
{ |
274 |
return ReadVector3Array(ReadInt32()); |
275 |
} |
276 |
|
277 |
public Vector3[] ReadVector3Array(int length) |
278 |
{ |
279 |
var data = new Vector3[length]; |
280 |
|
281 |
for (int i = 0; i < data.Length; i++) |
282 |
data[i] = ReadVector3(); |
283 |
|
284 |
return data; |
285 |
} |
286 |
|
287 |
public Plane ReadPlane() |
288 |
{ |
289 |
return new Plane(ReadVector3(), ReadSingle()); |
290 |
} |
291 |
|
292 |
public Plane[] ReadPlaneVarArray() |
293 |
{ |
294 |
return ReadPlaneArray(ReadInt32()); |
295 |
} |
296 |
|
297 |
public Plane[] ReadPlaneArray(int length) |
298 |
{ |
299 |
var data = new Plane[length]; |
300 |
|
301 |
for (int i = 0; i < data.Length; i++) |
302 |
data[i] = ReadPlane(); |
303 |
|
304 |
return data; |
305 |
} |
306 |
|
307 |
public Quaternion ReadQuaternion() |
308 |
{ |
309 |
return new Quaternion(ReadSingle(), ReadSingle(), ReadSingle(), -ReadSingle()); |
310 |
} |
311 |
|
312 |
public Quaternion ReadCompressedQuaternion() |
313 |
{ |
314 |
return Quaternion.CreateFromAxisAngle(Vector3.UnitX, ReadInt16() * rotationAngleScale) |
315 |
* Quaternion.CreateFromAxisAngle(Vector3.UnitY, ReadInt16() * rotationAngleScale) |
316 |
* Quaternion.CreateFromAxisAngle(Vector3.UnitZ, ReadInt16() * rotationAngleScale); |
317 |
} |
318 |
|
319 |
public BoundingBox ReadBoundingBox() |
320 |
{ |
321 |
return new BoundingBox(ReadVector3(), ReadVector3()); |
322 |
} |
323 |
|
324 |
public Matrix ReadMatrix4x3() |
325 |
{ |
326 |
Matrix m; |
327 |
m.M11 = ReadSingle(); |
328 |
m.M12 = ReadSingle(); |
329 |
m.M13 = ReadSingle(); |
330 |
m.M14 = 0.0f; |
331 |
m.M21 = ReadSingle(); |
332 |
m.M22 = ReadSingle(); |
333 |
m.M23 = ReadSingle(); |
334 |
m.M24 = 0.0f; |
335 |
m.M31 = ReadSingle(); |
336 |
m.M32 = ReadSingle(); |
337 |
m.M33 = ReadSingle(); |
338 |
m.M34 = 0.0f; |
339 |
m.M41 = ReadSingle(); |
340 |
m.M42 = ReadSingle(); |
341 |
m.M43 = ReadSingle(); |
342 |
m.M44 = 1.0f; |
343 |
return m; |
344 |
} |
345 |
|
346 |
public Color ReadColor() |
347 |
{ |
348 |
uint color = ReadUInt32(); |
349 |
|
350 |
var r = (byte)((color >> 16) & 0xff); |
351 |
var g = (byte)((color >> 08) & 0xff); |
352 |
var b = (byte)((color >> 00) & 0xff); |
353 |
var a = (byte)((color >> 24) & 0xff); |
354 |
|
355 |
return new Color(r, g, b, a); |
356 |
} |
357 |
|
358 |
public Color[] ReadColorArray(int length) |
359 |
{ |
360 |
var data = new Color[length]; |
361 |
|
362 |
for (int i = 0; i < data.Length; i++) |
363 |
data[i] = ReadColor(); |
364 |
|
365 |
return data; |
366 |
} |
367 |
|
368 |
public string ReadString(int maxLength) |
369 |
{ |
370 |
var bytes = ReadBytes(maxLength); |
371 |
|
372 |
for (int i = 0; i < bytes.Length; i++) |
373 |
{ |
374 |
if (bytes[i] == 0) |
375 |
return encoding.GetString(bytes, 0, i); |
376 |
} |
377 |
|
378 |
return encoding.GetString(bytes); |
379 |
} |
380 |
|
381 |
public string ReadCString() |
382 |
{ |
383 |
var buffer = new List<byte>(64); |
384 |
byte b; |
385 |
|
386 |
while ((b = ReadByte()) != 0) |
387 |
buffer.Add(b); |
388 |
|
389 |
return encoding.GetString(buffer.ToArray()); |
390 |
} |
391 |
|
392 |
public InstanceDescriptor ReadInstance() |
393 |
{ |
394 |
return instanceFile.ResolveLink(ReadInt32()); |
395 |
} |
396 |
|
397 |
public InstanceDescriptor[] ReadInstanceArray(int length) |
398 |
{ |
399 |
var data = new InstanceDescriptor[length]; |
400 |
|
401 |
for (int i = 0; i < data.Length; i++) |
402 |
data[i] = ReadInstance(); |
403 |
|
404 |
return data; |
405 |
} |
406 |
|
407 |
public InstanceDescriptor ReadLink() |
408 |
{ |
409 |
return instanceFile.GetDescriptor(ReadInt32()); |
410 |
} |
411 |
|
412 |
public InstanceDescriptor[] ReadLinkArray(int length) |
413 |
{ |
414 |
var data = new InstanceDescriptor[length]; |
415 |
|
416 |
for (int i = 0; i < data.Length; i++) |
417 |
data[i] = ReadLink(); |
418 |
|
419 |
return data; |
420 |
} |
421 |
|
422 |
private void FillBuffer(int count) |
423 |
{ |
424 |
int offset = 0; |
425 |
|
426 |
while (count > 0) |
427 |
{ |
428 |
int read = stream.Read(buffer, offset, count); |
429 |
|
430 |
if (read == 0) |
431 |
throw new EndOfStreamException(); |
432 |
|
433 |
offset += read; |
434 |
count -= read; |
435 |
} |
436 |
} |
437 |
} |
438 |
} |