-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBinaryDataReader.cs
159 lines (141 loc) · 4.65 KB
/
BinaryDataReader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace XCom2ModTool
{
internal abstract class BinaryDataReader : IDisposable
{
private bool leaveOpen;
private Stack<uint> stack = new Stack<uint>();
private List<UnrealPackages.ObjectReference> refs = new List<UnrealPackages.ObjectReference>();
public BinaryDataReader(string path, bool leaveOpen = false)
{
Reader = new BinaryReader(File.OpenRead(path));
this.leaveOpen = leaveOpen;
}
public BinaryDataReader(BinaryReader reader, bool leaveOpen = false)
{
Reader = reader;
this.leaveOpen = leaveOpen;
}
public void Dispose()
{
if (!leaveOpen)
{
Reader?.Dispose();
}
}
public void Detach()
{
if (!leaveOpen)
{
Reader?.Dispose();
}
Reader = null;
}
public void Attach(BinaryReader reader, bool leaveOpen = false)
{
Detach();
Reader = reader;
this.leaveOpen = leaveOpen;
}
public BinaryReader Reader { get; private set; }
public bool EndOfStream => Position == Reader.BaseStream.Length;
protected long Position
{
get => Reader.BaseStream.Position;
set => Reader.BaseStream.Position = value;
}
protected byte[] Bytes(int count) => Reader.ReadBytes(count);
protected byte[] Bytes(uint count)
{
if (count > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
return Reader.ReadBytes((int)count);
}
protected ulong U64() => Reader.ReadUInt64();
protected ulong U64HL()
{
ulong high = U32();
ulong low = U32();
return (high << 32) | low;
}
protected uint U32() => Reader.ReadUInt32();
protected ushort U16() => Reader.ReadUInt16();
protected byte U8() => Reader.ReadByte();
protected int I32() => Reader.ReadInt32();
protected bool Bool() => Reader.ReadUInt32() != 0;
protected Guid FGuid() => new Guid(Bytes(16));
public UnrealPackages.ObjectReference Ref()
{
var objRef = new UnrealPackages.ObjectReference { Raw = I32() };
refs.Add(objRef);
return objRef;
}
public IEnumerable<UnrealPackages.ObjectReference> Refs() => refs;
public string Name(UnrealPackages.GlobalName[] names)
{
var index = U32();
var suffix = U32();
var name = names[index].Name;
if (suffix != 0)
{
name += $"_{suffix - 1}";
}
return name;
}
public uint Push(uint value)
{
stack.Push(value);
return value;
}
public uint Pop() => stack.Pop();
protected string FString()
{
var length = Reader.ReadInt32();
if (Math.Abs(length) > 4096)
{
//throw new InvalidDataException("Suspect FString exceeds 4096 bytes");
}
if (length < 0)
{
var bytes = Reader.ReadBytes(-length);
return Encoding.Unicode.GetString(bytes, 0, bytes.Length - 2);
}
else
{
var bytes = Reader.ReadBytes(length);
return Encoding.ASCII.GetString(bytes, 0, bytes.Length - 1);
}
}
protected IDisposable Detour(long position = 0) => new BinaryDetour(Reader, position);
protected T[] Array<T>(uint count, Func<T> construct)
{
if (count > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
return Enumerable.Range(0, (int)count).Select(x => construct()).ToArray();
}
protected T[] Array<T>(Func<T> construct) => Array(U32(), construct);
private class BinaryDetour : IDisposable
{
private BinaryReader reader;
private long position;
public BinaryDetour(BinaryReader reader, long newPosition)
{
this.reader = reader;
this.position = reader.BaseStream.Position;
reader.BaseStream.Position = newPosition;
}
public void Dispose()
{
reader.BaseStream.Position = position;
}
}
}
}