source: OniSplit/Metadata/CopyVisitor.cs@ 1174

Last change on this file since 1174 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 9.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4
5namespace Oni.Metadata
6{
7 internal class CopyVisitor : MetaTypeVisitor
8 {
9 #region Private data
10 private BinaryReader input;
11 private BinaryWriter output;
12 private Action<CopyVisitor> callback;
13 private Stack<ActiveField> activeFields;
14 private MetaType topLevelType;
15 private MetaType currentType;
16 private byte[] buffer;
17 private int fieldSize;
18 private int position;
19 #endregion
20
21 #region private class ActiveField
22
23 private class ActiveField
24 {
25 public Field Field;
26 public int Index;
27
28 public ActiveField(Field field)
29 {
30 Field = field;
31 Index = -1;
32 }
33 }
34
35 #endregion
36
37 public CopyVisitor(BinaryReader reader, BinaryWriter writer, Action<CopyVisitor> callback)
38 {
39 this.input = reader;
40 this.output = writer;
41 this.callback = callback;
42 this.activeFields = new Stack<ActiveField>();
43 }
44
45 public MetaType TopLevelType => topLevelType;
46
47 public MetaType Type => currentType;
48
49 public Field Field
50 {
51 get
52 {
53 if (activeFields.Count == 0)
54 return null;
55
56 return activeFields.Peek().Field;
57 }
58 }
59
60 public int Position => position;
61
62 public byte GetByte() => buffer[0];
63
64 public short GetInt16() => (short)(buffer[0] | (buffer[1] << 8));
65
66 public ushort GetUInt16() => (ushort)(buffer[0] | (buffer[1] << 8));
67
68 public int GetInt32() => buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
69
70 public uint GetUInt32() => (uint)buffer[0] | ((uint)buffer[1] << 8) | ((uint)buffer[2] << 16) | ((uint)buffer[3] << 24);
71
72 public void SetInt32(int value)
73 {
74 buffer[0] = (byte)value;
75 buffer[1] = (byte)(value >> 8);
76 buffer[2] = (byte)(value >> 16);
77 buffer[3] = (byte)(value >> 24);
78 }
79
80 public string GetCurrentFieldName()
81 {
82 if (activeFields.Count == 0)
83 return null;
84
85 List<string> names = new List<string>();
86
87 foreach (ActiveField state in activeFields)
88 {
89 if (string.IsNullOrEmpty(state.Field.Name))
90 return null;
91
92 if (state.Index >= 0)
93 names.Add(string.Format("{0}[{1}]", state.Field.Name, state.Index));
94 else
95 names.Add(state.Field.Name);
96 }
97
98 names.Add(topLevelType.Name);
99 names.Reverse();
100
101 return string.Join(".", names.ToArray());
102 }
103
104 public string GetParentFieldName()
105 {
106 if (activeFields.Count == 0)
107 return null;
108
109 List<string> names = new List<string>();
110
111 foreach (ActiveField state in activeFields)
112 {
113 if (string.IsNullOrEmpty(state.Field.Name))
114 return null;
115
116 if (state.Index >= 0)
117 names.Add(string.Format("{0}[{1}]", state.Field.Name, state.Index));
118 else
119 names.Add(state.Field.Name);
120 }
121
122 names.Add(topLevelType.Name);
123 names.Reverse();
124 names.RemoveAt(names.Count - 1);
125
126 return string.Join(".", names.ToArray());
127 }
128
129 public override void VisitByte(MetaByte type) => CopyBytes(type);
130 public override void VisitInt16(MetaInt16 type) => CopyBytes(type);
131 public override void VisitUInt16(MetaUInt16 type) => CopyBytes(type);
132 public override void VisitInt32(MetaInt32 type) => CopyBytes(type);
133 public override void VisitUInt32(MetaUInt32 type) => CopyBytes(type);
134 public override void VisitInt64(MetaInt64 type) => CopyBytes(type);
135 public override void VisitUInt64(MetaUInt64 type) => CopyBytes(type);
136 public override void VisitFloat(MetaFloat type) => CopyBytes(type);
137 public override void VisitColor(MetaColor type) => CopyBytes(type);
138 public override void VisitRawOffset(MetaRawOffset type) => CopyBytes(type);
139 public override void VisitSepOffset(MetaSepOffset type) => CopyBytes(type);
140 public override void VisitPointer(MetaPointer type) => CopyBytes(type);
141 public override void VisitBoundingBox(MetaBoundingBox type) => CopyBytes(type);
142 public override void VisitBoundingSphere(MetaBoundingSphere type) => CopyBytes(type);
143 public override void VisitMatrix4x3(MetaMatrix4x3 type) => CopyBytes(type);
144 public override void VisitPlane(MetaPlane type) => CopyBytes(type);
145 public override void VisitQuaternion(MetaQuaternion type) => CopyBytes(type);
146 public override void VisitVector2(MetaVector2 type) => CopyBytes(type);
147 public override void VisitVector3(MetaVector3 type) => CopyBytes(type);
148
149 private void CopyBytes(MetaType type)
150 {
151 BeginCopy(type, 1);
152 EndCopy();
153 }
154
155 public override void VisitString(MetaString type)
156 {
157 BeginCopy(type, 1);
158
159 bool zeroFound = false;
160
161 for (int i = 0; i < type.Size; i++)
162 {
163 if (zeroFound)
164 buffer[i] = 0;
165 else if (buffer[i] == 0)
166 zeroFound = true;
167 }
168
169 EndCopy();
170 }
171
172 public override void VisitPadding(MetaPadding type)
173 {
174 BeginCopy(type, 1);
175
176 if (type.FillByte == 0)
177 {
178 Array.Clear(buffer, 0, type.Size);
179 }
180 else
181 {
182 for (int i = 0; i < type.Size; i++)
183 buffer[i] = type.FillByte;
184 }
185
186 EndCopy();
187 }
188
189 public override void VisitStruct(MetaStruct type)
190 {
191 if (topLevelType == null)
192 topLevelType = type;
193
194 foreach (Field field in type.Fields)
195 {
196 BeginCopyField(field);
197 field.Type.Accept(this);
198 EndCopyField(field);
199 }
200 }
201
202 internal void BeginCopyField(Field field)
203 {
204 activeFields.Push(new ActiveField(field));
205 }
206
207 internal void EndCopyField(Field field)
208 {
209 if (activeFields.Peek().Field != field)
210 throw new InvalidOperationException();
211
212 activeFields.Pop();
213 }
214
215 public override void VisitArray(MetaArray type)
216 {
217 CopyArray(type.ElementType, type.Count);
218 }
219
220 public override void VisitVarArray(MetaVarArray type)
221 {
222 BeginCopyField(type.CountField);
223 type.CountField.Type.Accept(this);
224 EndCopyField(type.CountField);
225
226 int length;
227
228 if (type.CountField.Type == MetaType.Int16)
229 length = GetInt16();
230 else
231 length = GetInt32();
232
233 if (length < 0)
234 throw new InvalidDataException(string.Format("Invalid array length: 0x{0:x} at offset 0x{1:x}", length, position));
235
236 CopyArray(type.ElementType, length);
237 }
238
239 private void CopyArray(MetaType elementType, int count)
240 {
241 if (elementType.IsBlittable)
242 {
243 BeginCopy(elementType, count);
244 EndCopy();
245 return;
246 }
247
248 for (int i = 0; i < count; i++)
249 {
250 BeginCopyArrayElement(i);
251 elementType.Accept(this);
252 EndCopyArrayElement(i);
253 }
254 }
255
256 private void BeginCopyArrayElement(int index)
257 {
258 if (activeFields.Count == 0)
259 return;
260
261 activeFields.Peek().Index = index;
262 }
263
264 private void EndCopyArrayElement(int index)
265 {
266 if (activeFields.Count == 0)
267 return;
268
269 ActiveField field = activeFields.Peek();
270
271 if (field.Index != index)
272 throw new InvalidOperationException();
273
274 field.Index = -1;
275 }
276
277 private void BeginCopy(MetaType type, int count)
278 {
279 currentType = type;
280
281 fieldSize = type.Size * count;
282
283 if (buffer == null || buffer.Length < fieldSize)
284 buffer = new byte[fieldSize * 2];
285
286 input.Read(buffer, 0, fieldSize);
287 }
288
289 private void EndCopy()
290 {
291 if (callback != null)
292 callback(this);
293
294 if (output != null)
295 output.Write(buffer, 0, fieldSize);
296
297 position += fieldSize;
298 }
299 }
300}
Note: See TracBrowser for help on using the repository browser.