1 |
using System; |
2 |
using System.Collections; |
3 |
using System.Collections.Generic; |
4 |
using System.IO; |
5 |
using System.Text; |
6 |
using System.Text.RegularExpressions; |
7 |
using System.Xml; |
8 |
using System.Reflection; |
9 |
|
10 |
namespace Oni |
11 |
{ |
12 |
#if !NETFX4 |
13 |
internal delegate void Action(); |
14 |
internal delegate void Action<T>(T arg1); |
15 |
internal delegate void Action<T1, T2>(T1 arg1, T2 args); |
16 |
internal delegate TResult Func<T1, TResult>(T1 arg1); |
17 |
internal delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2); |
18 |
internal delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3); |
19 |
#endif |
20 |
|
21 |
internal static class Utils |
22 |
{ |
23 |
private static string version; |
24 |
|
25 |
public static string Version |
26 |
{ |
27 |
get |
28 |
{ |
29 |
if (version == null) |
30 |
{ |
31 |
#if NETCORE |
32 |
version = typeof(Utils).GetTypeInfo().Assembly.GetName().Version.ToString(); |
33 |
#else |
34 |
version = typeof(Utils).Assembly.GetName().Version.ToString(); |
35 |
#endif |
36 |
} |
37 |
|
38 |
return version; |
39 |
} |
40 |
} |
41 |
|
42 |
public static string TagToString(int tag) |
43 |
{ |
44 |
var chars = new char[4]; |
45 |
|
46 |
chars[0] = (char)((tag >> 00) & 0xff); |
47 |
chars[1] = (char)((tag >> 08) & 0xff); |
48 |
chars[2] = (char)((tag >> 16) & 0xff); |
49 |
chars[3] = (char)((tag >> 24) & 0xff); |
50 |
|
51 |
return new string(chars); |
52 |
} |
53 |
|
54 |
public static int Align4(int value) => (value + 0x03) & ~0x03; |
55 |
public static int Align32(int value) => (value + 0x1f) & ~0x1f; |
56 |
|
57 |
public static short ByteSwap(short value) |
58 |
{ |
59 |
return (short)((value >> 8) | (value << 8)); |
60 |
} |
61 |
|
62 |
public static int ByteSwap(int value) |
63 |
{ |
64 |
value = (value >> 16) | (value << 16); |
65 |
return ((value >> 8) & 0x00ff00ff) | ((value & 0x00ff00ff) << 8); |
66 |
} |
67 |
|
68 |
public static bool ArrayEquals<T>(T[] a1, T[] a2) |
69 |
{ |
70 |
if (a1 == a2) |
71 |
return true; |
72 |
|
73 |
if (a1 == null || a2 == null) |
74 |
return false; |
75 |
|
76 |
if (a1.Length != a2.Length) |
77 |
return false; |
78 |
|
79 |
var comparer = EqualityComparer<T>.Default; |
80 |
|
81 |
for (int i = 0; i < a1.Length; i++) |
82 |
{ |
83 |
if (!comparer.Equals(a1[i], a2[i])) |
84 |
return false; |
85 |
} |
86 |
|
87 |
return true; |
88 |
} |
89 |
|
90 |
public static string CleanupTextureName(string name) |
91 |
{ |
92 |
name = name.Replace('/', '_'); |
93 |
|
94 |
if (name == "<none>") |
95 |
name = "none"; |
96 |
|
97 |
return name; |
98 |
} |
99 |
|
100 |
private static readonly char[] wildcards = { '*', '?', '.' }; |
101 |
|
102 |
private static void WildcardToRegex(string wexp, StringBuilder regexp) |
103 |
{ |
104 |
for (int startIndex = 0; startIndex < wexp.Length;) |
105 |
{ |
106 |
int i = wexp.IndexOfAny(wildcards, startIndex); |
107 |
|
108 |
if (i == -1) |
109 |
{ |
110 |
regexp.Append(wexp, startIndex, wexp.Length - startIndex); |
111 |
break; |
112 |
} |
113 |
|
114 |
regexp.Append(wexp, startIndex, i - startIndex); |
115 |
|
116 |
if (wexp[i] == '.') |
117 |
regexp.Append("\\."); |
118 |
if (wexp[i] == '*') |
119 |
regexp.Append(".*"); |
120 |
else if (wexp[i] == '?') |
121 |
regexp.Append('.'); |
122 |
|
123 |
startIndex = i + 1; |
124 |
} |
125 |
} |
126 |
|
127 |
public static Regex WildcardToRegex(string wexp) |
128 |
{ |
129 |
if (string.IsNullOrEmpty(wexp)) |
130 |
return null; |
131 |
|
132 |
var regexp = new StringBuilder(); |
133 |
WildcardToRegex(wexp, regexp); |
134 |
return new Regex(regexp.ToString(), RegexOptions.Singleline); |
135 |
} |
136 |
|
137 |
public static Regex WildcardToRegex(List<string> wexps) |
138 |
{ |
139 |
if (wexps.Count == 0) |
140 |
return null; |
141 |
|
142 |
var regex = new StringBuilder(); |
143 |
|
144 |
foreach (var wexp in wexps) |
145 |
{ |
146 |
if (regex.Length != 0) |
147 |
regex.Append('|'); |
148 |
|
149 |
regex.Append('('); |
150 |
WildcardToRegex(wexp, regex); |
151 |
regex.Append(')'); |
152 |
} |
153 |
|
154 |
Console.WriteLine(regex.ToString()); |
155 |
|
156 |
return new Regex(regex.ToString(), RegexOptions.Singleline); |
157 |
} |
158 |
|
159 |
private static byte[] buffer1; |
160 |
private static byte[] buffer2; |
161 |
|
162 |
public static bool AreFilesEqual(string filePath1, string filePath2) |
163 |
{ |
164 |
if (buffer1 == null) |
165 |
{ |
166 |
buffer1 = new byte[32768]; |
167 |
buffer2 = new byte[32768]; |
168 |
} |
169 |
|
170 |
using (var s1 = File.OpenRead(filePath1)) |
171 |
using (var s2 = File.OpenRead(filePath2)) |
172 |
{ |
173 |
if (s1.Length != s2.Length) |
174 |
return false; |
175 |
|
176 |
while (true) |
177 |
{ |
178 |
int r1 = s1.Read(buffer1, 0, buffer1.Length); |
179 |
int r2 = s2.Read(buffer2, 0, buffer2.Length); |
180 |
|
181 |
if (r1 != r2) |
182 |
return false; |
183 |
|
184 |
if (r1 == 0) |
185 |
return true; |
186 |
|
187 |
for (int i = 0; i < r1; i++) |
188 |
{ |
189 |
if (buffer1[i] != buffer2[i]) |
190 |
return false; |
191 |
} |
192 |
} |
193 |
} |
194 |
} |
195 |
|
196 |
|
197 |
public static bool IsFlagsEnum(Type enumType) |
198 |
{ |
199 |
#if NETCORE |
200 |
return (enumType.GetTypeInfo().GetCustomAttributes(typeof(FlagsAttribute), false).Any()); |
201 |
#else |
202 |
return (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0); |
203 |
#endif |
204 |
} |
205 |
|
206 |
public static void WriteEnum(Type enumType) |
207 |
{ |
208 |
bool isFlags = IsFlagsEnum(enumType); |
209 |
Type underlyingType = Enum.GetUnderlyingType(enumType); |
210 |
|
211 |
if (isFlags) |
212 |
Console.WriteLine("flags {0}", enumType.Name); |
213 |
else |
214 |
Console.WriteLine("enum {0}", enumType.Name); |
215 |
|
216 |
foreach (string name in Enum.GetNames(enumType)) |
217 |
{ |
218 |
object value = Enum.Parse(enumType, name); |
219 |
|
220 |
if (isFlags) |
221 |
{ |
222 |
if (underlyingType == typeof(ulong)) |
223 |
Console.WriteLine("\t{0} = 0x{1:X16}", name, Convert.ToUInt64(value)); |
224 |
else |
225 |
Console.WriteLine("\t{0} = 0x{1:X8}", name, Convert.ToUInt32(value)); |
226 |
} |
227 |
else |
228 |
{ |
229 |
if (underlyingType == typeof(ulong)) |
230 |
Console.WriteLine("\t{0} = {1}", name, Convert.ToUInt64(value)); |
231 |
else |
232 |
Console.WriteLine("\t{0} = {1}", name, Convert.ToInt32(value)); |
233 |
} |
234 |
} |
235 |
|
236 |
Console.WriteLine(); |
237 |
} |
238 |
|
239 |
public static IEnumerable<T> Reverse<T>(this IList<T> list) |
240 |
{ |
241 |
for (int i = list.Count - 1; i >= 0; i--) |
242 |
yield return list[i]; |
243 |
} |
244 |
|
245 |
public static T First<T>(this IList<T> list) => list[0]; |
246 |
|
247 |
public static T Last<T>(this IList<T> list) => list[list.Count - 1]; |
248 |
|
249 |
public static T LastOrDefault<T>(this List<T> list) |
250 |
{ |
251 |
if (list.Count == 0) |
252 |
return default(T); |
253 |
|
254 |
return list[list.Count - 1]; |
255 |
} |
256 |
|
257 |
public static float[] Negate(this float[] values) |
258 |
{ |
259 |
float[] result = new float[values.Length]; |
260 |
|
261 |
for (int i = 0; i < values.Length; i++) |
262 |
result[i] = -values[i]; |
263 |
|
264 |
return result; |
265 |
} |
266 |
|
267 |
public static string CommonPrefix(List<string> strings) |
268 |
{ |
269 |
string first = strings[0]; |
270 |
|
271 |
for (int prefixLength = 0; prefixLength < first.Length; prefixLength++) |
272 |
{ |
273 |
for (int i = 1; i < strings.Count; i++) |
274 |
{ |
275 |
string s = strings[i]; |
276 |
|
277 |
if (prefixLength >= s.Length || first[prefixLength] != s[prefixLength]) |
278 |
return first.Substring(0, prefixLength); |
279 |
} |
280 |
} |
281 |
|
282 |
return first; |
283 |
} |
284 |
|
285 |
public static void SkipSequence(this XmlReader xml, string name) |
286 |
{ |
287 |
while (xml.IsStartElement(name)) |
288 |
xml.Skip(); |
289 |
} |
290 |
|
291 |
public static bool SkipEmpty(this XmlReader xml) |
292 |
{ |
293 |
if (!xml.IsEmptyElement) |
294 |
return false; |
295 |
|
296 |
xml.Skip(); |
297 |
return true; |
298 |
} |
299 |
|
300 |
//public static int CommonPrefixLength(string s1, string s2) |
301 |
//{ |
302 |
// int length = Math.Min(s1.Length, s2.Length); |
303 |
|
304 |
// for (int i = 0; i < length; i++) |
305 |
// { |
306 |
// if (s1[i] != s2[i]) |
307 |
// return i; |
308 |
// } |
309 |
|
310 |
// return length; |
311 |
//} |
312 |
} |
313 |
|
314 |
/// <summary> |
315 |
/// A couple of IEnumerable extensions so we can run even on .NET 2.0 |
316 |
/// </summary> |
317 |
internal static class Enumerable |
318 |
{ |
319 |
public static bool Any<T>(this IEnumerable<T> source) |
320 |
{ |
321 |
foreach (var t in source) |
322 |
return true; |
323 |
|
324 |
return false; |
325 |
} |
326 |
|
327 |
public static bool Any<T>(this IEnumerable<T> source, Func<T, bool> predicate) |
328 |
{ |
329 |
foreach (var t in source) |
330 |
{ |
331 |
if (predicate(t)) |
332 |
return true; |
333 |
} |
334 |
|
335 |
return false; |
336 |
} |
337 |
|
338 |
public static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate) |
339 |
{ |
340 |
foreach (var t in source) |
341 |
{ |
342 |
if (!predicate(t)) |
343 |
return false; |
344 |
} |
345 |
|
346 |
return true; |
347 |
} |
348 |
|
349 |
public static IEnumerable<T> OfType<T>(this System.Collections.IEnumerable source) |
350 |
where T : class |
351 |
{ |
352 |
foreach (var obj in source) |
353 |
{ |
354 |
var t = obj as T; |
355 |
|
356 |
if (t != null) |
357 |
yield return t; |
358 |
} |
359 |
} |
360 |
|
361 |
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) |
362 |
where T : class |
363 |
{ |
364 |
var set = new Dictionary<T, bool>(); |
365 |
bool hasNull = false; |
366 |
|
367 |
foreach (var t in source) |
368 |
{ |
369 |
if (t == null) |
370 |
{ |
371 |
if (!hasNull) |
372 |
{ |
373 |
hasNull = true; |
374 |
yield return null; |
375 |
} |
376 |
} |
377 |
else if (!set.ContainsKey(t)) |
378 |
{ |
379 |
set.Add(t, true); |
380 |
yield return t; |
381 |
} |
382 |
} |
383 |
} |
384 |
|
385 |
public static int Count<T>(this IEnumerable<T> source, Func<T, bool> predicate) |
386 |
{ |
387 |
var count = 0; |
388 |
|
389 |
foreach (var t in source) |
390 |
if (predicate(t)) |
391 |
count++; |
392 |
|
393 |
return count; |
394 |
} |
395 |
|
396 |
public static IEnumerable<T> Concatenate<T>(this IEnumerable<T> first, IEnumerable<T> second) |
397 |
{ |
398 |
foreach (var t in first) |
399 |
yield return t; |
400 |
|
401 |
foreach (var t in second) |
402 |
yield return t; |
403 |
} |
404 |
|
405 |
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate) |
406 |
{ |
407 |
foreach (var t in source) |
408 |
{ |
409 |
if (predicate(t)) |
410 |
yield return t; |
411 |
} |
412 |
} |
413 |
|
414 |
public static bool IsEmpty<T>(this IEnumerable<T> source) |
415 |
{ |
416 |
foreach (var t in source) |
417 |
return true; |
418 |
|
419 |
return false; |
420 |
} |
421 |
|
422 |
public static T First<T>(this IEnumerable<T> source) |
423 |
{ |
424 |
foreach (var t in source) |
425 |
return t; |
426 |
|
427 |
throw new InvalidOperationException(); |
428 |
} |
429 |
|
430 |
public static T First<T>(this IEnumerable<T> source, Func<T, bool> predicate) |
431 |
{ |
432 |
foreach (var t in source) |
433 |
{ |
434 |
if (predicate(t)) |
435 |
return t; |
436 |
} |
437 |
|
438 |
throw new InvalidOperationException(); |
439 |
} |
440 |
|
441 |
public static T FirstOrDefault<T>(this IEnumerable<T> source) |
442 |
{ |
443 |
foreach (var t in source) |
444 |
return t; |
445 |
|
446 |
return default(T); |
447 |
} |
448 |
|
449 |
public static T FirstOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate) |
450 |
{ |
451 |
foreach (var t in source) |
452 |
{ |
453 |
if (predicate(t)) |
454 |
return t; |
455 |
} |
456 |
|
457 |
return default(T); |
458 |
} |
459 |
|
460 |
public static IEnumerable<TOut> Select<TIn, TOut>(this IEnumerable<TIn> source, Func<TIn, TOut> selector) |
461 |
{ |
462 |
foreach (var t in source) |
463 |
yield return selector(t); |
464 |
} |
465 |
|
466 |
public static IEnumerable<TOut> SelectMany<TIn, TOut>(this IEnumerable<TIn> source, Func<TIn, IEnumerable<TOut>> selector) |
467 |
{ |
468 |
foreach (var tin in source) |
469 |
{ |
470 |
foreach (var tout in selector(tin)) |
471 |
yield return tout; |
472 |
} |
473 |
} |
474 |
|
475 |
public static float Max(this IEnumerable<float> source) |
476 |
{ |
477 |
var max = float.MinValue; |
478 |
|
479 |
foreach (var value in source) |
480 |
max = Math.Max(max, value); |
481 |
|
482 |
return max; |
483 |
} |
484 |
|
485 |
public static float Min<T>(this IEnumerable<T> source, Func<T, float> selector) |
486 |
{ |
487 |
var min = float.MaxValue; |
488 |
|
489 |
foreach (var value in source) |
490 |
min = Math.Min(min, selector(value)); |
491 |
|
492 |
return min; |
493 |
} |
494 |
|
495 |
public static int Min<T>(this IEnumerable<T> source, Func<T, int> selector) |
496 |
{ |
497 |
var min = int.MaxValue; |
498 |
|
499 |
foreach (var value in source) |
500 |
min = Math.Min(min, selector(value)); |
501 |
|
502 |
return min; |
503 |
} |
504 |
|
505 |
public static float Min(this IEnumerable<float> source) |
506 |
{ |
507 |
var min = float.MaxValue; |
508 |
|
509 |
foreach (var value in source) |
510 |
min = Math.Min(min, value); |
511 |
|
512 |
return min; |
513 |
} |
514 |
|
515 |
public static float Max<T>(this IEnumerable<T> source, Func<T, float> selector) |
516 |
{ |
517 |
var max = float.MinValue; |
518 |
|
519 |
foreach (var value in source) |
520 |
max = Math.Max(max, selector(value)); |
521 |
|
522 |
return max; |
523 |
} |
524 |
|
525 |
public static int Max(this IEnumerable<int> source) |
526 |
{ |
527 |
int max = int.MinValue; |
528 |
|
529 |
foreach (var value in source) |
530 |
{ |
531 |
if (value > max) |
532 |
max = value; |
533 |
} |
534 |
|
535 |
return max; |
536 |
} |
537 |
|
538 |
public static int Max<T>(this IEnumerable<T> source, Func<T, int> selector) |
539 |
{ |
540 |
int max = int.MinValue; |
541 |
|
542 |
foreach (var item in source) |
543 |
{ |
544 |
var value = selector(item); |
545 |
|
546 |
if (value > max) |
547 |
max = value; |
548 |
} |
549 |
|
550 |
return max; |
551 |
} |
552 |
|
553 |
public static TOutput[] ConvertAll<TInput, TOutput>(this TInput[] input, Func<TInput, TOutput> converter) |
554 |
{ |
555 |
var output = new TOutput[input.Length]; |
556 |
|
557 |
for (int i = 0; i < output.Length; i++) |
558 |
output[i] = converter(input[i]); |
559 |
|
560 |
return output; |
561 |
} |
562 |
|
563 |
public static int Sum<T>(this IEnumerable<T> source, Func<T, int> selector) |
564 |
{ |
565 |
int sum = 0; |
566 |
|
567 |
foreach (var value in source) |
568 |
sum += selector(value); |
569 |
|
570 |
return sum; |
571 |
} |
572 |
|
573 |
public static IEnumerable<T> Repeat<T>(T value, int count) |
574 |
{ |
575 |
for (int i = 0; i < count; i++) |
576 |
yield return value; |
577 |
} |
578 |
|
579 |
public static T[] ToArray<T>(this IEnumerable<T> source) |
580 |
{ |
581 |
var collection = source as ICollection<T>; |
582 |
|
583 |
if (collection != null) |
584 |
{ |
585 |
var result = new T[collection.Count]; |
586 |
collection.CopyTo(result, 0); |
587 |
return result; |
588 |
} |
589 |
|
590 |
return new List<T>(source).ToArray(); |
591 |
} |
592 |
|
593 |
public static List<T> ToList<T>(this IEnumerable<T> source) => new List<T>(source); |
594 |
|
595 |
public static IEnumerable<T> Ring<T>(this IEnumerable<T> source) |
596 |
{ |
597 |
foreach (T t in source) |
598 |
{ |
599 |
yield return t; |
600 |
} |
601 |
|
602 |
foreach (T t in source) |
603 |
{ |
604 |
yield return t; |
605 |
break; |
606 |
} |
607 |
} |
608 |
|
609 |
public static IEnumerable<T> Skip<T>(this IEnumerable<T> source, int count) |
610 |
{ |
611 |
foreach (T t in source) |
612 |
{ |
613 |
if (count <= 0) |
614 |
yield return t; |
615 |
|
616 |
count--; |
617 |
} |
618 |
} |
619 |
} |
620 |
|
621 |
internal struct EmptyArray<T> |
622 |
{ |
623 |
public static readonly T[] Value = new T[0]; |
624 |
} |
625 |
|
626 |
internal struct ReadOnlyArray<T> |
627 |
{ |
628 |
private readonly T[] array; |
629 |
|
630 |
public ReadOnlyArray(T[] array) |
631 |
{ |
632 |
this.array = array; |
633 |
} |
634 |
|
635 |
public int Length => array.Length; |
636 |
public T this[int index] => array[index]; |
637 |
} |
638 |
|
639 |
internal class TreeIterator<T> : IEnumerable<T> |
640 |
{ |
641 |
private readonly IEnumerable<T> roots; |
642 |
private readonly Func<T, IEnumerable<T>> children; |
643 |
|
644 |
public TreeIterator(IEnumerable<T> roots, Func<T, IEnumerable<T>> children) |
645 |
{ |
646 |
this.roots = roots; |
647 |
this.children = children; |
648 |
} |
649 |
|
650 |
public class Enumerator : IEnumerator<T> |
651 |
{ |
652 |
public bool MoveNext() |
653 |
{ |
654 |
throw new NotImplementedException(); |
655 |
} |
656 |
|
657 |
public T Current |
658 |
{ |
659 |
get { throw new NotImplementedException(); } |
660 |
} |
661 |
|
662 |
object IEnumerator.Current => Current; |
663 |
|
664 |
public void Dispose() |
665 |
{ |
666 |
} |
667 |
|
668 |
public void Reset() |
669 |
{ |
670 |
throw new NotSupportedException(); |
671 |
} |
672 |
} |
673 |
|
674 |
public IEnumerator<T> GetEnumerator() => new Enumerator(); |
675 |
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(); |
676 |
} |
677 |
} |
678 |
|
679 |
#if !NETFX4 |
680 |
namespace System.Runtime.CompilerServices |
681 |
{ |
682 |
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] |
683 |
internal sealed class ExtensionAttribute : Attribute |
684 |
{ |
685 |
} |
686 |
} |
687 |
#endif |