source: OniSplit/Xml/RawXmlImporter.cs@ 1117

Last change on this file since 1117 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: 7.4 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Xml;
4using Oni.Imaging;
5using Oni.Metadata;
6
7namespace Oni.Xml
8{
9 internal class RawXmlImporter : IMetaTypeVisitor
10 {
11 private static readonly Func<string, float> floatConverter = XmlConvert.ToSingle;
12 private static readonly Func<string, byte> byteConverter = XmlConvert.ToByte;
13 private readonly XmlReader xml;
14 private readonly BinaryWriter writer;
15 private Stack<int> startOffsetStack;
16
17 public RawXmlImporter(XmlReader xml, BinaryWriter writer)
18 {
19 this.xml = xml;
20 this.writer = writer;
21 }
22
23 protected XmlReader Xml => xml;
24
25 protected BinaryWriter Writer => writer;
26
27 protected void BeginStruct(int startPosition)
28 {
29 startOffsetStack = new Stack<int>();
30 startOffsetStack.Push(startPosition);
31 }
32
33 #region IMetaTypeVisitor Members
34
35 void IMetaTypeVisitor.VisitEnum(MetaEnum type)
36 {
37 type.XmlToBinary(xml, writer);
38 }
39
40 void IMetaTypeVisitor.VisitByte(MetaByte type)
41 {
42 writer.Write(XmlConvert.ToByte(xml.ReadElementContentAsString()));
43 }
44
45 void IMetaTypeVisitor.VisitInt16(MetaInt16 type)
46 {
47 writer.Write(XmlConvert.ToInt16(xml.ReadElementContentAsString()));
48 }
49
50 void IMetaTypeVisitor.VisitUInt16(MetaUInt16 type)
51 {
52 writer.Write(XmlConvert.ToUInt16(xml.ReadElementContentAsString()));
53 }
54
55 void IMetaTypeVisitor.VisitInt32(MetaInt32 type)
56 {
57 writer.Write(xml.ReadElementContentAsInt());
58 }
59
60 void IMetaTypeVisitor.VisitUInt32(MetaUInt32 type)
61 {
62 writer.Write(XmlConvert.ToUInt32(xml.ReadElementContentAsString()));
63 }
64
65 void IMetaTypeVisitor.VisitInt64(MetaInt64 type)
66 {
67 writer.Write(xml.ReadElementContentAsLong());
68 }
69
70 void IMetaTypeVisitor.VisitUInt64(MetaUInt64 type)
71 {
72 writer.Write(XmlConvert.ToUInt64(xml.ReadElementContentAsString()));
73 }
74
75 void IMetaTypeVisitor.VisitFloat(MetaFloat type)
76 {
77 writer.Write(xml.ReadElementContentAsFloat());
78 }
79
80 void IMetaTypeVisitor.VisitColor(MetaColor type)
81 {
82 byte[] values = xml.ReadElementContentAsArray(byteConverter);
83
84 if (values.Length > 3)
85 writer.Write(new Color(values[0], values[1], values[2], values[3]));
86 else
87 writer.Write(new Color(values[0], values[1], values[2]));
88 }
89
90 void IMetaTypeVisitor.VisitVector2(MetaVector2 type)
91 {
92 writer.Write(xml.ReadElementContentAsArray(floatConverter, 2));
93 }
94
95 void IMetaTypeVisitor.VisitVector3(MetaVector3 type)
96 {
97 writer.Write(xml.ReadElementContentAsArray(floatConverter, 3));
98 }
99
100 void IMetaTypeVisitor.VisitMatrix4x3(MetaMatrix4x3 type)
101 {
102 writer.WriteMatrix4x3(xml.ReadElementContentAsMatrix43());
103 }
104
105 void IMetaTypeVisitor.VisitPlane(MetaPlane type)
106 {
107 writer.Write(xml.ReadElementContentAsArray(floatConverter, 4));
108 }
109
110 void IMetaTypeVisitor.VisitQuaternion(MetaQuaternion type)
111 {
112 writer.Write(xml.ReadElementContentAsQuaternion());
113 }
114
115 void IMetaTypeVisitor.VisitBoundingSphere(MetaBoundingSphere type)
116 {
117 ReadFields(type.Fields);
118 }
119
120 void IMetaTypeVisitor.VisitBoundingBox(MetaBoundingBox type)
121 {
122 ReadFields(type.Fields);
123 }
124
125 void IMetaTypeVisitor.VisitRawOffset(MetaRawOffset type)
126 {
127 throw new NotImplementedException();
128 }
129
130 void IMetaTypeVisitor.VisitSepOffset(MetaSepOffset type)
131 {
132 throw new NotImplementedException();
133 }
134
135 void IMetaTypeVisitor.VisitString(MetaString type)
136 {
137 writer.Write(xml.ReadElementContentAsString(), type.Count);
138 }
139
140 void IMetaTypeVisitor.VisitPadding(MetaPadding type)
141 {
142 writer.Write(type.FillByte, type.Count);
143 }
144
145 void IMetaTypeVisitor.VisitPointer(MetaPointer type)
146 {
147 throw new NotImplementedException();
148 }
149
150 void IMetaTypeVisitor.VisitStruct(MetaStruct type)
151 {
152 ReadFields(type.Fields);
153 }
154
155 void IMetaTypeVisitor.VisitArray(MetaArray type)
156 {
157 int count = ReadArray(type.ElementType, type.Count);
158
159 if (count < type.Count)
160 writer.Skip((type.Count - count) * type.ElementType.Size);
161 }
162
163 void IMetaTypeVisitor.VisitVarArray(MetaVarArray type)
164 {
165 int countFieldPosition = writer.Position;
166 int count;
167
168 if (type.CountField.Type == MetaType.Int16)
169 {
170 writer.WriteInt16(0);
171 count = ReadArray(type.ElementType, UInt16.MaxValue);
172 }
173 else
174 {
175 writer.Write(0);
176 count = ReadArray(type.ElementType, Int32.MaxValue);
177 }
178
179 int position = writer.Position;
180 writer.Position = countFieldPosition;
181
182 if (type.CountField.Type == MetaType.Int16)
183 writer.WriteUInt16(count);
184 else
185 writer.Write(count);
186
187 writer.Position = position;
188 }
189
190 #endregion
191
192 private void ReadFields(IEnumerable<Field> fields)
193 {
194 xml.ReadStartElement();
195 xml.MoveToContent();
196
197 foreach (Field field in fields)
198 {
199 try
200 {
201 field.Type.Accept(this);
202 }
203 catch (Exception ex)
204 {
205 var lineInfo = xml as IXmlLineInfo;
206 int line = lineInfo != null ? lineInfo.LineNumber : 0;
207 throw new InvalidOperationException(string.Format("Cannot read field '{0}' (line {1})", field.Name, line), ex);
208 }
209 }
210
211 xml.ReadEndElement();
212 }
213
214 protected void ReadStruct(MetaStruct s)
215 {
216 foreach (Field field in s.Fields)
217 {
218 try
219 {
220 field.Type.Accept(this);
221 }
222 catch (Exception ex)
223 {
224 throw new InvalidOperationException(string.Format("Cannot read field '{0}'", field.Name), ex);
225 }
226 }
227 }
228
229 private int ReadArray(MetaType elementType, int maxCount)
230 {
231 if (xml.IsEmptyElement)
232 {
233 xml.Read();
234 return 0;
235 }
236
237 xml.ReadStartElement();
238 xml.MoveToContent();
239
240 var localName = xml.LocalName;
241 int count = 0;
242
243 for (; count < maxCount && xml.IsStartElement(localName); count++)
244 {
245 startOffsetStack.Push(writer.Position);
246 elementType.Accept(this);
247 startOffsetStack.Pop();
248 }
249
250 xml.ReadEndElement();
251
252 return count;
253 }
254 }
255}
Note: See TracBrowser for help on using the repository browser.