1 |
using System; |
2 |
using System.Collections.Generic; |
3 |
using System.Xml; |
4 |
using Oni.Imaging; |
5 |
using Oni.Metadata; |
6 |
|
7 |
namespace 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 |
} |