using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Xml; using System.Reflection; namespace Oni { #if !NETFX4 internal delegate void Action(); internal delegate void Action(T arg1); internal delegate void Action(T1 arg1, T2 args); internal delegate TResult Func(T1 arg1); internal delegate TResult Func(T1 arg1, T2 arg2); internal delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); #endif internal static class Utils { private static string version; public static string Version { get { if (version == null) { #if NETCORE version = typeof(Utils).GetTypeInfo().Assembly.GetName().Version.ToString(); #else version = typeof(Utils).Assembly.GetName().Version.ToString(); #endif } return version; } } public static string TagToString(int tag) { var chars = new char[4]; chars[0] = (char)((tag >> 00) & 0xff); chars[1] = (char)((tag >> 08) & 0xff); chars[2] = (char)((tag >> 16) & 0xff); chars[3] = (char)((tag >> 24) & 0xff); return new string(chars); } public static int Align4(int value) => (value + 0x03) & ~0x03; public static int Align32(int value) => (value + 0x1f) & ~0x1f; public static short ByteSwap(short value) { return (short)((value >> 8) | (value << 8)); } public static int ByteSwap(int value) { value = (value >> 16) | (value << 16); return ((value >> 8) & 0x00ff00ff) | ((value & 0x00ff00ff) << 8); } public static bool ArrayEquals(T[] a1, T[] a2) { if (a1 == a2) return true; if (a1 == null || a2 == null) return false; if (a1.Length != a2.Length) return false; var comparer = EqualityComparer.Default; for (int i = 0; i < a1.Length; i++) { if (!comparer.Equals(a1[i], a2[i])) return false; } return true; } public static string CleanupTextureName(string name) { name = name.Replace('/', '_'); if (name == "") name = "none"; return name; } private static readonly char[] wildcards = { '*', '?', '.' }; private static void WildcardToRegex(string wexp, StringBuilder regexp) { for (int startIndex = 0; startIndex < wexp.Length;) { int i = wexp.IndexOfAny(wildcards, startIndex); if (i == -1) { regexp.Append(wexp, startIndex, wexp.Length - startIndex); break; } regexp.Append(wexp, startIndex, i - startIndex); if (wexp[i] == '.') regexp.Append("\\."); if (wexp[i] == '*') regexp.Append(".*"); else if (wexp[i] == '?') regexp.Append('.'); startIndex = i + 1; } } public static Regex WildcardToRegex(string wexp) { if (string.IsNullOrEmpty(wexp)) return null; var regexp = new StringBuilder(); WildcardToRegex(wexp, regexp); return new Regex(regexp.ToString(), RegexOptions.Singleline); } public static Regex WildcardToRegex(List wexps) { if (wexps.Count == 0) return null; var regex = new StringBuilder(); foreach (var wexp in wexps) { if (regex.Length != 0) regex.Append('|'); regex.Append('('); WildcardToRegex(wexp, regex); regex.Append(')'); } Console.WriteLine(regex.ToString()); return new Regex(regex.ToString(), RegexOptions.Singleline); } private static byte[] buffer1; private static byte[] buffer2; public static bool AreFilesEqual(string filePath1, string filePath2) { if (buffer1 == null) { buffer1 = new byte[32768]; buffer2 = new byte[32768]; } using (var s1 = File.OpenRead(filePath1)) using (var s2 = File.OpenRead(filePath2)) { if (s1.Length != s2.Length) return false; while (true) { int r1 = s1.Read(buffer1, 0, buffer1.Length); int r2 = s2.Read(buffer2, 0, buffer2.Length); if (r1 != r2) return false; if (r1 == 0) return true; for (int i = 0; i < r1; i++) { if (buffer1[i] != buffer2[i]) return false; } } } } public static bool IsFlagsEnum(Type enumType) { #if NETCORE return (enumType.GetTypeInfo().GetCustomAttributes(typeof(FlagsAttribute), false).Any()); #else return (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0); #endif } public static void WriteEnum(Type enumType) { bool isFlags = IsFlagsEnum(enumType); Type underlyingType = Enum.GetUnderlyingType(enumType); if (isFlags) Console.WriteLine("flags {0}", enumType.Name); else Console.WriteLine("enum {0}", enumType.Name); foreach (string name in Enum.GetNames(enumType)) { object value = Enum.Parse(enumType, name); if (isFlags) { if (underlyingType == typeof(ulong)) Console.WriteLine("\t{0} = 0x{1:X16}", name, Convert.ToUInt64(value)); else Console.WriteLine("\t{0} = 0x{1:X8}", name, Convert.ToUInt32(value)); } else { if (underlyingType == typeof(ulong)) Console.WriteLine("\t{0} = {1}", name, Convert.ToUInt64(value)); else Console.WriteLine("\t{0} = {1}", name, Convert.ToInt32(value)); } } Console.WriteLine(); } public static IEnumerable Reverse(this IList list) { for (int i = list.Count - 1; i >= 0; i--) yield return list[i]; } public static T First(this IList list) => list[0]; public static T Last(this IList list) => list[list.Count - 1]; public static T LastOrDefault(this List list) { if (list.Count == 0) return default(T); return list[list.Count - 1]; } public static float[] Negate(this float[] values) { float[] result = new float[values.Length]; for (int i = 0; i < values.Length; i++) result[i] = -values[i]; return result; } public static string CommonPrefix(List strings) { string first = strings[0]; for (int prefixLength = 0; prefixLength < first.Length; prefixLength++) { for (int i = 1; i < strings.Count; i++) { string s = strings[i]; if (prefixLength >= s.Length || first[prefixLength] != s[prefixLength]) return first.Substring(0, prefixLength); } } return first; } public static void SkipSequence(this XmlReader xml, string name) { while (xml.IsStartElement(name)) xml.Skip(); } public static bool SkipEmpty(this XmlReader xml) { if (!xml.IsEmptyElement) return false; xml.Skip(); return true; } //public static int CommonPrefixLength(string s1, string s2) //{ // int length = Math.Min(s1.Length, s2.Length); // for (int i = 0; i < length; i++) // { // if (s1[i] != s2[i]) // return i; // } // return length; //} } /// /// A couple of IEnumerable extensions so we can run even on .NET 2.0 /// internal static class Enumerable { public static bool Any(this IEnumerable source) { foreach (var t in source) return true; return false; } public static bool Any(this IEnumerable source, Func predicate) { foreach (var t in source) { if (predicate(t)) return true; } return false; } public static bool All(this IEnumerable source, Func predicate) { foreach (var t in source) { if (!predicate(t)) return false; } return true; } public static IEnumerable OfType(this System.Collections.IEnumerable source) where T : class { foreach (var obj in source) { var t = obj as T; if (t != null) yield return t; } } public static IEnumerable Distinct(this IEnumerable source) where T : class { var set = new Dictionary(); bool hasNull = false; foreach (var t in source) { if (t == null) { if (!hasNull) { hasNull = true; yield return null; } } else if (!set.ContainsKey(t)) { set.Add(t, true); yield return t; } } } public static int Count(this IEnumerable source, Func predicate) { var count = 0; foreach (var t in source) if (predicate(t)) count++; return count; } public static IEnumerable Concatenate(this IEnumerable first, IEnumerable second) { foreach (var t in first) yield return t; foreach (var t in second) yield return t; } public static IEnumerable Where(this IEnumerable source, Func predicate) { foreach (var t in source) { if (predicate(t)) yield return t; } } public static bool IsEmpty(this IEnumerable source) { foreach (var t in source) return true; return false; } public static T First(this IEnumerable source) { foreach (var t in source) return t; throw new InvalidOperationException(); } public static T First(this IEnumerable source, Func predicate) { foreach (var t in source) { if (predicate(t)) return t; } throw new InvalidOperationException(); } public static T FirstOrDefault(this IEnumerable source) { foreach (var t in source) return t; return default(T); } public static T FirstOrDefault(this IEnumerable source, Func predicate) { foreach (var t in source) { if (predicate(t)) return t; } return default(T); } public static IEnumerable Select(this IEnumerable source, Func selector) { foreach (var t in source) yield return selector(t); } public static IEnumerable SelectMany(this IEnumerable source, Func> selector) { foreach (var tin in source) { foreach (var tout in selector(tin)) yield return tout; } } public static float Max(this IEnumerable source) { var max = float.MinValue; foreach (var value in source) max = Math.Max(max, value); return max; } public static float Min(this IEnumerable source, Func selector) { var min = float.MaxValue; foreach (var value in source) min = Math.Min(min, selector(value)); return min; } public static int Min(this IEnumerable source, Func selector) { var min = int.MaxValue; foreach (var value in source) min = Math.Min(min, selector(value)); return min; } public static float Min(this IEnumerable source) { var min = float.MaxValue; foreach (var value in source) min = Math.Min(min, value); return min; } public static float Max(this IEnumerable source, Func selector) { var max = float.MinValue; foreach (var value in source) max = Math.Max(max, selector(value)); return max; } public static int Max(this IEnumerable source) { int max = int.MinValue; foreach (var value in source) { if (value > max) max = value; } return max; } public static int Max(this IEnumerable source, Func selector) { int max = int.MinValue; foreach (var item in source) { var value = selector(item); if (value > max) max = value; } return max; } public static TOutput[] ConvertAll(this TInput[] input, Func converter) { var output = new TOutput[input.Length]; for (int i = 0; i < output.Length; i++) output[i] = converter(input[i]); return output; } public static int Sum(this IEnumerable source, Func selector) { int sum = 0; foreach (var value in source) sum += selector(value); return sum; } public static IEnumerable Repeat(T value, int count) { for (int i = 0; i < count; i++) yield return value; } public static T[] ToArray(this IEnumerable source) { var collection = source as ICollection; if (collection != null) { var result = new T[collection.Count]; collection.CopyTo(result, 0); return result; } return new List(source).ToArray(); } public static List ToList(this IEnumerable source) => new List(source); public static IEnumerable Ring(this IEnumerable source) { foreach (T t in source) { yield return t; } foreach (T t in source) { yield return t; break; } } public static IEnumerable Skip(this IEnumerable source, int count) { foreach (T t in source) { if (count <= 0) yield return t; count--; } } } internal struct EmptyArray { public static readonly T[] Value = new T[0]; } internal struct ReadOnlyArray { private readonly T[] array; public ReadOnlyArray(T[] array) { this.array = array; } public int Length => array.Length; public T this[int index] => array[index]; } internal class TreeIterator : IEnumerable { private readonly IEnumerable roots; private readonly Func> children; public TreeIterator(IEnumerable roots, Func> children) { this.roots = roots; this.children = children; } public class Enumerator : IEnumerator { public bool MoveNext() { throw new NotImplementedException(); } public T Current { get { throw new NotImplementedException(); } } object IEnumerator.Current => Current; public void Dispose() { } public void Reset() { throw new NotSupportedException(); } } public IEnumerator GetEnumerator() => new Enumerator(); IEnumerator IEnumerable.GetEnumerator() => new Enumerator(); } } #if !NETFX4 namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] internal sealed class ExtensionAttribute : Attribute { } } #endif