source: OniSplit/Xml/XmlReaderExtensions.cs@ 1116

Last change on this file since 1116 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: 10.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Xml;
5
6namespace Oni.Xml
7{
8 internal static class XmlReaderExtensions
9 {
10 private static readonly char[] emptyChars = new char[0];
11
12 [ThreadStatic]
13 private static char[] charBuffer;
14
15 private static char[] CharBuffer
16 {
17 get
18 {
19 if (charBuffer == null)
20 charBuffer = new char[16384];
21
22 return charBuffer;
23 }
24 }
25
26 public static IEnumerable<string> ReadElementContentAsList(this XmlReader xml)
27 {
28 if (xml.SkipEmpty())
29 yield break;
30
31 xml.ReadStartElement();
32
33 if (xml.NodeType == XmlNodeType.EndElement)
34 {
35 xml.ReadEndElement();
36 yield break;
37 }
38
39#if DNET
40 char[] buffer = CharBuffer;
41 int offset = 0;
42 int length;
43
44 while ((length = xml.ReadValueChunk(buffer, offset, buffer.Length - offset)) > 0 || offset > 0)
45 {
46 bool hasMore = length != 0;
47 length += offset;
48 offset = 0;
49
50 for (int i = 0; i < length; i++)
51 {
52 if (Char.IsWhiteSpace(buffer[i]))
53 continue;
54
55 int start = i;
56
57 do
58 i++;
59 while (i < length && !Char.IsWhiteSpace(buffer[i]));
60
61 if (i == length && hasMore)
62 {
63 offset = i - start;
64 Array.Copy(buffer, start, buffer, 0, offset);
65 break;
66 }
67
68 yield return new string(buffer, start, i - start);
69 }
70 }
71
72 while (xml.NodeType != XmlNodeType.EndElement)
73 xml.Read();
74#else
75 string buffer = xml.ReadContentAsString();
76
77 for (int i = 0; i < buffer.Length; i++)
78 {
79 if (char.IsWhiteSpace(buffer[i]))
80 continue;
81
82 int start = i;
83
84 do
85 i++;
86 while (i < buffer.Length && !char.IsWhiteSpace(buffer[i]));
87
88 yield return buffer.Substring(start, i - start);
89 }
90#endif
91
92 xml.ReadEndElement();
93 }
94
95 private static void ReadArrayCore<T>(XmlReader xml, Func<string, T> parser, List<T> list)
96 {
97 foreach (var text in xml.ReadElementContentAsList())
98 list.Add(parser(text));
99 }
100
101 public static T[] ReadElementContentAsArray<T>(this XmlReader xml, Func<string, T> parser)
102 {
103 var list = new List<T>();
104 ReadArrayCore<T>(xml, parser, list);
105 return list.ToArray();
106 }
107
108 public static T[] ReadElementContentAsArray<T>(this XmlReader xml, Func<string, T> converter, int count)
109 {
110 var list = new List<T>(count);
111 ReadArrayCore(xml, converter, list);
112 var array = new T[count];
113 list.CopyTo(0, array, 0, count);
114 return array;
115 }
116
117 public static void ReadElementContentAsArray<T>(this XmlReader xml, Func<string, T> parser, T[] array)
118 {
119 var text = xml.ReadElementContentAsString();
120 var tokens = text.Split(emptyChars, StringSplitOptions.RemoveEmptyEntries);
121
122 for (int i = 0; i < array.Length; i++)
123 {
124 if (i < tokens.Length)
125 array[i] = parser(tokens[i]);
126 else
127 array[i] = default(T);
128 }
129 }
130
131 public static T[] ReadElementContentAsArray<T>(this XmlReader xml, Func<string, T> parser, string name)
132 {
133 string text;
134
135 if (name == null)
136 text = xml.ReadElementContentAsString();
137 else
138 text = xml.ReadElementContentAsString(name, string.Empty);
139
140 var tokens = text.Split(emptyChars, StringSplitOptions.RemoveEmptyEntries);
141 return tokens.ConvertAll(parser);
142 }
143
144 private static T[] ReadArray<T>(this XmlReader xml, Func<string, T> parser, int count)
145 {
146 var text = xml.ReadElementContentAsString();
147 var tokens = text.Split(emptyChars, StringSplitOptions.RemoveEmptyEntries);
148 var values = tokens.ConvertAll(parser);
149
150 Array.Resize(ref values, count);
151
152 return values;
153 }
154
155 public static T[] ReadElementContentAsArray<T>(this XmlReader xml, Func<string, T> converter, int count, string name)
156 {
157 var array = xml.ReadElementContentAsArray<T>(converter, name);
158 Array.Resize(ref array, count);
159 return array;
160 }
161
162
163 public static Vector2 ReadElementContentAsVector2(this XmlReader xml, string name = null)
164 {
165 var values = xml.ReadElementContentAsArray(XmlConvert.ToSingle, 2, name);
166
167 return new Vector2(values[0], values[1]);
168 }
169
170 public static Vector3 ReadElementContentAsVector3(this XmlReader xml, string name = null)
171 {
172 var values = xml.ReadElementContentAsArray(XmlConvert.ToSingle, 3);
173
174 return new Vector3(values[0], values[1], values[2]);
175 }
176
177 public static Vector4 ReadElementContentAsVector4(this XmlReader xml)
178 {
179 var values = xml.ReadElementContentAsArray(XmlConvert.ToSingle, 4);
180
181 return new Vector4(values[0], values[1], values[2], values[3]);
182 }
183
184 public static Quaternion ReadElementContentAsEulerXYZ(this XmlReader xml)
185 {
186 var values = xml.ReadElementContentAsArray(XmlConvert.ToSingle, 3);
187
188 return Quaternion.CreateFromEulerXYZ(values[0], values[1], values[2]);
189 }
190
191 public static Quaternion ReadElementContentAsQuaternion(this XmlReader xml, string name = null)
192 {
193 var quat = Quaternion.Identity;
194
195 if (xml.IsEmptyElement)
196 {
197 xml.Skip();
198 }
199 else
200 {
201 if (name == null)
202 xml.ReadStartElement();
203 else
204 xml.ReadStartElement(name);
205
206 if (xml.NodeType == XmlNodeType.Text)
207 {
208 var values = xml.ReadArray(XmlConvert.ToSingle, 4);
209
210 quat = new Quaternion(values[0], values[1], values[2], -values[3]);
211 }
212 else
213 {
214 var transforms = new List<Quaternion>();
215
216 while (xml.IsStartElement())
217 {
218 switch (xml.LocalName)
219 {
220 case "rotate":
221 var rotate = xml.ReadElementContentAsVector4();
222 transforms.Add(Quaternion.CreateFromAxisAngle(rotate.XYZ, MathHelper.ToRadians(rotate.W)));
223 break;
224 case "euler":
225 transforms.Add(xml.ReadElementContentAsEulerXYZ());
226 break;
227 default:
228 throw new XmlException(string.Format("Unknown element {0}", xml.LocalName));
229 }
230 }
231
232 foreach (var transform in Utils.Reverse(transforms))
233 quat *= transform;
234 }
235
236 xml.ReadEndElement();
237 }
238
239 return quat;
240 }
241
242 public static Matrix ReadElementContentAsMatrix43(this XmlReader xml, string name = null)
243 {
244 var matrix = Matrix.Identity;
245
246 if (xml.IsEmptyElement)
247 {
248 xml.Skip();
249 }
250 else
251 {
252 if (name == null)
253 xml.ReadStartElement();
254 else
255 xml.ReadStartElement(name);
256
257 if (xml.NodeType == XmlNodeType.Text)
258 {
259 var values = xml.ReadArray(XmlConvert.ToSingle, 12);
260
261 matrix = new Matrix(
262 values[0], values[1], values[2], 0.0f,
263 values[3], values[4], values[5], 0.0f,
264 values[6], values[7], values[8], 0.0f,
265 values[9], values[10], values[11], 1.0f);
266 }
267 else
268 {
269 var transforms = new List<Matrix>();
270
271 while (xml.IsStartElement())
272 {
273 switch (xml.LocalName)
274 {
275 case "translate":
276 transforms.Add(Matrix.CreateTranslation(xml.ReadElementContentAsVector3()));
277 break;
278 case "rotate":
279 var rotate = xml.ReadElementContentAsVector4();
280 transforms.Add(Matrix.CreateFromAxisAngle(rotate.XYZ, MathHelper.ToRadians(rotate.W)));
281 break;
282 case "euler":
283 transforms.Add(xml.ReadElementContentAsEulerXYZ().ToMatrix());
284 break;
285 case "scale":
286 transforms.Add(Matrix.CreateScale(xml.ReadElementContentAsVector3()));
287 break;
288 default:
289 throw new XmlException(string.Format("Unknown element {0}", xml.LocalName));
290 }
291 }
292
293 foreach (var transform in Utils.Reverse(transforms))
294 matrix *= transform;
295 }
296
297 xml.ReadEndElement();
298 }
299
300 return matrix;
301 }
302 }
303}
Note: See TracBrowser for help on using the repository browser.