948 lines
25 KiB
C#

//
// ExtensionMethods.cs - various useful (maybe?) extension methods
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2011-2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Text;
namespace UniversalEditor
{
public static class ExtensionMethods
{
public static long GetItemOffset(this List<string> list, int index, int additionalPadding = 0)
{
long offset = 0;
for (int i = 0; i < index; i++)
{
if (list[i] == null)
{
offset += additionalPadding;
}
else
{
offset += list[i].Length + additionalPadding;
}
}
return offset;
}
public static bool get_EndOfStream(this System.IO.Stream stream)
{
return (stream.Position == stream.Length);
}
/// <summary>
/// Gets an int value representing the subset of bits from a single Byte.
/// </summary>
/// <param name="b">The Byte used to get the subset of bits from.</param>
/// <param name="offset">The offset of bits starting from the right.</param>
/// <param name="count">The number of bits to read.</param>
/// <returns>
/// An int value representing the subset of bits.
/// </returns>
/// <remarks>
/// Given -> b = 00110101
/// A call to GetBits(b, 2, 4)
/// GetBits looks at the following bits in the byte -> 00{1101}00
/// Returns 1101 as an int (13)
/// </remarks>
public static int GetBits(this byte value, int offset, int count)
{
return (value >> offset) & ((1 << count) - 1);
}
public static int GetBits(this short value, int offset, int count)
{
return (value >> offset) & ((1 << count) - 1);
}
public static int GetBits(this int value, int offset, int count)
{
return (value >> offset) & ((1 << count) - 1);
}
public static byte[] ToBits(this byte value)
{
byte[] bits = new byte[8];
for (int i = 0; i < bits.Length; i++)
{
bits[i] = (byte)value.GetBits(i, 1);
}
return bits;
}
[CLSCompliant(false)]
public static int GetBits(this ushort value, int offset, int count)
{
return (value >> offset) & ((1 << count) - 1);
}
public static void AddRange(this System.Collections.Specialized.StringCollection coll, params string[] values)
{
coll.AddRange(values);
}
public static bool Match(this Array array1, Array array2)
{
if (array1.Length != array2.Length)
{
return false;
}
System.Collections.IEnumerator en1 = array1.GetEnumerator();
System.Collections.IEnumerator en2 = array2.GetEnumerator();
en1.MoveNext();
en2.MoveNext();
try
{
while (en1.Current != null)
{
if (en2.Current == null) return false;
if (!en1.Current.Equals(en2.Current)) return false;
en1.MoveNext();
en2.MoveNext();
}
}
catch (InvalidOperationException)
{
}
return true;
}
/// <summary>
/// Returns <see langword="true" /> if <paramref name="value" /> is equal
/// to any one of the values in <paramref name="anyOf" />.
/// </summary>
/// <returns><c>true</c>, if a match was found; <c>false</c> otherwise.</returns>
/// <param name="value">The value to test.</param>
/// <param name="anyOf">
/// An array of items of type <typeparamref name="T" /> to check equality
/// against <paramref name="value" />.
/// </param>
public static bool EqualsAny<T>(this IEquatable<T> value, params T[] anyOf)
{
for (int i = 0; i < anyOf.Length; i++)
{
T any = anyOf[i];
if (value.Equals(any))
{
return true;
}
}
return false;
}
public static bool ContainsAny(this string value, params string[] anyOf)
{
bool result;
for (int i = 0; i < anyOf.Length; i++)
{
string any = anyOf[i];
if (value.Contains(any))
{
result = true;
return result;
}
}
result = false;
return result;
}
public static bool ContainsAny(this string value, params char[] anyOf)
{
bool result;
for (int i = 0; i < anyOf.Length; i++)
{
char any = anyOf[i];
if (value.Contains(any.ToString()))
{
result = true;
return result;
}
}
result = false;
return result;
}
public static int IndexOfAny(this string value, params string[] anyOf)
{
int result;
for (int i = 0; i < anyOf.Length; i++)
{
string any = anyOf[i];
int index = value.IndexOf(any);
if (index > -1)
{
result = index;
return result;
}
}
result = -1;
return result;
}
public static string Capitalize(this string value)
{
string result;
if (string.IsNullOrEmpty(value))
{
result = value;
}
else
{
if (value.Length == 1)
{
result = value.ToUpper();
}
else
{
result = value.Substring(0, 1).ToUpper() + value.Substring(1);
}
}
return result;
}
#region Splitting
public static T[] Split<T>(this string value, params char[] separator)
{
return value.Split<T>(separator, -1, StringSplitOptions.None);
}
public static T[] Split<T>(this string value, char[] separator, int count)
{
return value.Split<T>(separator, count, StringSplitOptions.None);
}
public static T[] Split<T>(this string value, char[] separator, int count, StringSplitOptions options)
{
string[] separators = new string[separator.Length];
for (int i = 0; i < separator.Length; i++)
{
separators[i] = separator[i].ToString();
}
return value.Split<T>(separators, count, options);
}
public static T[] Split<T>(this string value, params string[] separator)
{
return value.Split<T>(separator, -1, StringSplitOptions.None);
}
public static T[] Split<T>(this string value, string[] separator, int count)
{
return value.Split<T>(separator, count, StringSplitOptions.None);
}
public static T[] Split<T>(this string value, string[] separator, int count, StringSplitOptions options)
{
string[] splitt = null;
if (count < 0)
{
splitt = value.Split(separator, options);
}
else
{
splitt = value.Split(separator, count, options);
}
T[] values = new T[splitt.Length];
for (int i = 0; i < splitt.Length; i++)
{
if (!string.IsNullOrEmpty(splitt[i]))
{
values[i] = (T)Convert.ChangeType(splitt[i], typeof(T));
}
}
return values;
}
public static string[] Split(this string value, string separator)
{
return value.Split(new string[] { separator });
}
public static string[] Split(this string value, string[] separator)
{
return value.Split(separator, StringSplitOptions.None);
}
public static string[] Split(this string value, string[] separator, string ignore)
{
return value.Split(separator, ignore, ignore);
}
public static string[] Split(this string value, string[] separator, string ignoreBegin, string ignoreEnd)
{
return value.Split(separator, ignoreBegin, ignoreEnd, StringSplitOptions.None, -1);
}
public static string[] Split(this string value, string[] separator, StringSplitOptions options, int count, string ignore)
{
return value.Split(separator, ignore, ignore, options, count);
}
public static string[] Split(this string value, char[] separator, string ignore)
{
return value.Split(separator, ignore, ignore);
}
public static string[] Split(this string value, char[] separator, string ignoreBegin, string ignoreEnd)
{
return value.Split(separator, ignoreBegin, ignoreEnd, StringSplitOptions.None, -1);
}
public static string[] Split(this string value, char[] separator, string ignore, StringSplitOptions options, int count)
{
return value.Split(separator, ignore, ignore, options, count);
}
public static string[] Split(this string value, char[] separator, string ignoreBegin, string ignoreEnd, StringSplitOptions options, int count)
{
List<string> entries = new List<string>();
for (int i = 0; i < separator.Length; i++)
{
char sep = separator[i];
entries.Add(sep.ToString());
}
return value.Split(entries.ToArray(), ignoreBegin, ignoreEnd, options, count);
}
public static string[] Split(this string value, string[] separator, string ignoreBegin, string ignoreEnd, StringSplitOptions options, int count)
{
return value.Split(separator, ignoreBegin, ignoreEnd, options, count, true);
}
public static string[] Split(this string value, string[] separator, string ignoreBegin, string ignoreEnd, StringSplitOptions options, int count, bool discardIgnoreString)
{
List<string> entries = new List<string>();
bool ignoring = false;
bool continueOutside = false;
string next = string.Empty;
int i = 0;
while (i < value.Length)
{
if (i + ignoreBegin.Length > value.Length)
{
goto IL_70;
}
if (ignoring || !(value.Substring(i, ignoreBegin.Length) == ignoreBegin))
{
goto IL_70;
}
ignoring = true;
if (!discardIgnoreString)
{
next += ignoreBegin;
}
IL_16F:
i++;
continue;
IL_70:
if (i + ignoreEnd.Length <= value.Length)
{
if (ignoring && value.Substring(i, ignoreEnd.Length) == ignoreEnd)
{
ignoring = false;
if (!discardIgnoreString)
{
next += ignoreEnd;
}
goto IL_16F;
}
}
if (!ignoring)
{
int j = 0;
while (j < separator.Length)
{
if (i + separator[j].Length <= value.Length)
{
if (value.Substring(i, separator[j].Length) == separator[j])
{
if (count > -1 && (entries.Count >= count - 1))
{
next = value.Substring(i - next.Length);
entries.Add(next);
i = value.Length - 1;
break;
}
else
{
entries.Add(next);
next = string.Empty;
i += separator[j].Length - 1;
continueOutside = true;
}
}
}
j++;
continue;
}
}
if (continueOutside)
{
continueOutside = false;
goto IL_16F;
}
next += value[i];
goto IL_16F;
}
if (!string.IsNullOrEmpty(next))
{
entries.Add(next);
next = null;
}
return entries.ToArray();
}
#endregion
#region Endianness
[CLSCompliant(false)]
public static ushort SwapEndian(this ushort x)
{
return (ushort)(x >> 8 | (int)x << 8);
}
[CLSCompliant(false)]
public static ushort SwapEndian(this short x)
{
return ((ushort)x).SwapEndian();
}
[CLSCompliant(false)]
public static uint SwapEndian(this uint x)
{
return x >> 24 | (x << 8 & 16711680u) | (x >> 8 & 65280u) | x << 24;
}
[CLSCompliant(false)]
public static uint SwapEndian(this int x)
{
return ((uint)x).SwapEndian();
}
[CLSCompliant(false)]
public static ushort Swap(short x)
{
return x.SwapEndian();
}
[CLSCompliant(false)]
public static ushort Swap(ushort x)
{
return x.SwapEndian();
}
[CLSCompliant(false)]
public static uint Swap(int x)
{
return x.SwapEndian();
}
[CLSCompliant(false)]
public static uint Swap(uint x)
{
return x.SwapEndian();
}
#endregion
#region Number
[CLSCompliant(false)]
public static uint RoundUp(this uint number, int multiple)
{
uint result;
if ((ulong)number % (ulong)((long)multiple) == 0uL)
{
result = number;
}
else
{
result = (uint)((ulong)number + (ulong)((long)multiple - (long)((ulong)number % (ulong)((long)multiple))));
}
return result;
}
[CLSCompliant(false)]
public static ulong RoundUp(this ulong number, int multiple)
{
ulong result;
if ((ulong)number % (ulong)((long)multiple) == 0uL)
{
result = number;
}
else
{
result = (ulong)((ulong)number + (ulong)((long)multiple - (long)((ulong)number % (ulong)((long)multiple))));
}
return result;
}
public static int RoundUp(this int number, int multiple)
{
int result;
if (number % multiple == 0)
{
result = number;
}
else
{
result = number + (multiple - number % multiple);
}
return result;
}
public static int Digits(this int number)
{
return number.ToString().Length;
}
public static int Digits(this long number)
{
return number.ToString().Length;
}
public static short UpperWord(this short number)
{
return (short)(number >> 16);
}
public static short LowerWord(this short number)
{
return (short)(number & 0xFFFF);
}
[CLSCompliant(false)]
public static ushort UpperWord(this ushort number)
{
return (ushort)(number >> 16);
}
[CLSCompliant(false)]
public static ushort LowerWord(this ushort number)
{
return (ushort)(number & 0xFFFF);
}
public static int UpperWord(this int number)
{
return (int)(number >> 16);
}
public static int LowerWord(this int number)
{
return (int)(number & 0xFFFF);
}
[CLSCompliant(false)]
public static uint UpperWord(this uint number)
{
return (uint)(number >> 16);
}
[CLSCompliant(false)]
public static uint LowerWord(this uint number)
{
return (uint)(number & 0xFFFF);
}
public static long UpperWord(this long number)
{
return (long)(number >> 16);
}
public static long LowerWord(this long number)
{
return (long)(number & 0xFFFF);
}
[CLSCompliant(false)]
public static ulong UpperWord(this ulong number)
{
return (ulong)(number >> 16);
}
[CLSCompliant(false)]
public static ulong LowerWord(this ulong number)
{
return (ulong)(number & 0xFFFF);
}
#endregion
#region StreamReader Extensions
public static byte ReadByte(this System.IO.Stream stream, long offset)
{
stream.Position = offset;
return (byte)stream.ReadByte();
}
public static byte[] ReadBytes(this System.IO.Stream stream, long offset, int length)
{
byte[] array = new byte[length];
stream.Position = offset;
stream.Read(array, 0, length);
return array;
}
[CLSCompliant(false)]
public static byte[] ReadBytes(this System.IO.Stream stream, long offset, uint length)
{
return stream.ReadBytes(offset, (int)length);
}
public static short ReadShort(this System.IO.Stream stream, long offset)
{
byte[] array = new byte[2];
stream.Position = offset;
stream.Read(array, 0, 2);
return BitConverter.ToInt16(array, 0);
}
[CLSCompliant(false)]
public static ushort ReadUShort(this System.IO.Stream stream, long offset)
{
byte[] array = new byte[2];
stream.Position = offset;
stream.Read(array, 0, 2);
return BitConverter.ToUInt16(array, 0);
}
public static int ReadInt(this System.IO.Stream stream, long offset)
{
byte[] array = new byte[4];
stream.Position = offset;
stream.Read(array, 0, 4);
return BitConverter.ToInt32(array, 0);
}
[CLSCompliant(false)]
public static uint ReadUInt(this System.IO.Stream stream, long offset)
{
byte[] array = new byte[4];
stream.Position = offset;
stream.Read(array, 0, 4);
return BitConverter.ToUInt32(array, 0);
}
public static string ReadString(this System.IO.Stream stream, long offset, int maxLength, bool nullTerminator)
{
string text = string.Empty;
stream.Position = offset;
for (int i = 0; i < maxLength; i++)
{
char c = (char)stream.ReadByte();
if (c == '\0' && nullTerminator)
{
break;
}
text += c;
}
return text;
}
public static string ReadString(this System.IO.Stream stream, long offset, int maxLength)
{
return stream.ReadString(offset, maxLength, true);
}
public static string ReadString(this System.IO.Stream stream, long offset, int maxLength, Encoding encoding, bool nullTerminator)
{
stream.Position = offset;
byte[] array = new byte[maxLength];
stream.Read(array, 0, maxLength);
string text = encoding.GetString(array);
if (nullTerminator)
{
string arg_2D_0 = text;
char[] trimChars = new char[1];
text = arg_2D_0.TrimEnd(trimChars);
}
return text;
}
public static string ReadString(this System.IO.Stream stream, long offset, int maxLength, Encoding encoding)
{
return stream.ReadString(offset, maxLength, encoding, true);
}
public static byte[] ToByteArray(this System.IO.Stream stream)
{
long oldpos = stream.Position;
byte[] array = new byte[(int)((IntPtr)stream.Length)];
stream.Position = 0L;
stream.Read(array, 0, array.Length);
stream.Position = oldpos;
return array;
}
#endregion
#region StreamWriter Extensions
public static void Write(this System.IO.Stream stream, byte value)
{
stream.WriteByte(value);
}
public static void Write(this System.IO.Stream stream, short value)
{
stream.Write(BitConverter.GetBytes(value), 0, 2);
}
[CLSCompliant(false)]
public static void Write(this System.IO.Stream stream, ushort value)
{
stream.Write(BitConverter.GetBytes(value), 0, 2);
}
public static void Write(this System.IO.Stream stream, int value)
{
stream.Write(BitConverter.GetBytes(value), 0, 4);
}
[CLSCompliant(false)]
public static void Write(this System.IO.Stream stream, uint value)
{
stream.Write(BitConverter.GetBytes(value), 0, 4);
}
public static void Write(this System.IO.Stream stream, byte[] values)
{
stream.Write(values, 0, values.Length);
}
public static void Write(this System.IO.Stream stream, string value)
{
for (int i = 0; i < value.Length; i++)
{
stream.WriteByte((byte)value[i]);
}
}
public static void Write(this System.IO.Stream stream, string value, int length)
{
for (int i = 0; i < length; i++)
{
if (i < value.Length)
{
stream.WriteByte((byte)value[i]);
}
else
{
stream.WriteByte(0);
}
}
}
public static void Write(this System.IO.Stream stream, string value, int strLength, int length)
{
for (int i = 0; i < length; i++)
{
if (i < value.Length && i < strLength)
{
stream.WriteByte((byte)value[i]);
}
else
{
stream.WriteByte(0);
}
}
}
public static void Write(this System.IO.Stream stream, string value, int strLength, int length, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(value);
int num = 0;
while (bytes.Length > strLength)
{
num++;
bytes = encoding.GetBytes(value.Substring(0, value.Length - num));
}
for (int i = 0; i < length; i++)
{
if (i < bytes.Length && i < strLength)
{
stream.WriteByte(bytes[i]);
}
else
{
stream.WriteByte(0);
}
}
}
public static void Write(this System.IO.Stream output, System.IO.Stream input)
{
byte[] array = new byte[4096];
input.Position = 0L;
int count;
while ((count = input.Read(array, 0, array.Length)) > 0)
{
output.Write(array, 0, count);
}
}
public static void Write(this System.IO.Stream output, System.IO.MemoryStream input)
{
input.Position = 0L;
input.WriteTo(output);
}
public static void Write(this System.IO.Stream output, System.IO.Stream input, long offset, long length)
{
byte[] array = new byte[4096];
input.Position = offset;
int count;
while ((count = input.Read(array, 0, (input.Position + (long)array.Length > offset + length) ? ((int)(offset + length - input.Position)) : ((int)((long)array.Length)))) > 0)
{
output.Write(array, 0, count);
}
}
public static System.IO.MemoryStream Copy(this System.IO.Stream input)
{
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream((int)input.Length);
byte[] array = new byte[4096];
input.Position = 0L;
int count;
while ((count = input.Read(array, 0, array.Length)) > 0)
{
memoryStream.Write(array, 0, count);
}
return memoryStream;
}
public static System.IO.MemoryStream Copy(this System.IO.Stream input, long offset, int length)
{
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(length);
byte[] array = new byte[4096];
input.Position = offset;
int count;
while ((count = input.Read(array, 0, (input.Position + (long)array.Length > offset + (long)length) ? ((int)(offset + (long)length - input.Position)) : ((int)((long)array.Length)))) > 0)
{
memoryStream.Write(array, 0, count);
}
return memoryStream;
}
[CLSCompliant(false)]
public static System.IO.MemoryStream Copy(this System.IO.Stream input, long offset, uint length)
{
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream((int)length);
byte[] array = new byte[4096];
input.Position = offset;
int count;
while ((count = input.Read(array, 0, (input.Position + (long)array.Length > offset + (long)((ulong)length)) ? ((int)(offset + (long)((ulong)length) - input.Position)) : ((int)((long)array.Length)))) > 0)
{
memoryStream.Write(array, 0, count);
}
return memoryStream;
}
#endregion
#region Strings
public static bool IsAllUpperCase(this string str)
{
return (!(new System.Text.RegularExpressions.Regex("[a-z]")).IsMatch(str));
}
public static string UrlEncode(this string value)
{
return value;
}
public static string UrlDecode(this string input)
{
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
if (input[i] == '%')
{
char c = input[i + 1];
string arg_45_0 = c.ToString();
c = input[i + 2];
string numeric = arg_45_0 + c.ToString();
int hexcode = int.Parse(numeric, System.Globalization.NumberStyles.HexNumber);
i += 2;
output.Append((char)hexcode);
}
else
{
output.Append(input[i]);
}
}
return output.ToString();
}
public static bool Match(this string input, params string[] filters)
{
foreach (string filter in filters)
{
if (input.Match(filter)) return true;
}
return false;
}
public static bool Match(this string input, string filter)
{
if (filter == null)
return false;
string wildcardToRegex = "^" + System.Text.RegularExpressions.Regex.Escape(filter).Replace("\\*", ".*").Replace("\\?", ".") + "$";
return new System.Text.RegularExpressions.Regex(wildcardToRegex).IsMatch(input);
}
/// <summary>
/// Removes all characters past and including the first occurrence of a
/// NUL (0x00) byte from the given string.
/// </summary>
/// <returns>
/// All characters before the first occurrence of a NUL (0x00) byte in
/// <paramref name="value" />.
/// </returns>
/// <param name="value">The string to trim.</param>
public static string TrimNull(this string value)
{
int i = value.IndexOf('\0');
if (i > -1) return value.Substring(0, i);
return value;
}
public static string Format(this string input, Dictionary<string, string> formatWhat)
{
return Format(input, formatWhat, "$(", ")");
}
public static string Format(this string input, Dictionary<string, string> formatWhat, string formatBegin, string formatEnd)
{
string val = input;
foreach (KeyValuePair<string, string> kvp in formatWhat)
{
val = val.Replace(formatBegin + kvp.Key + formatEnd, kvp.Value);
}
return val;
}
/// <summary>
/// Inserts the specified value "count" times, with "spacing" characters between.
/// </summary>
/// <param name="count">The number of times to insert value.</param>
/// <param name="spacing">The amount of characters to leave between insertions.</param>
/// <param name="value">The value to insert.</param>
/// <returns></returns>
public static string Insert(this string input, int count, int spacing, string value)
{
int j = 0;
string retval = String.Empty;
for (int i = 0; i < count; i++)
{
retval += input.Substring(j, spacing) + value;
j += spacing;
}
retval += input.Substring(j);
return retval;
}
#endregion
#region Dictionary
public static KeyValuePair<TKey, TValue>[] ToArray<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
{
System.Collections.Generic.List<KeyValuePair<TKey, TValue>> list = new List<KeyValuePair<TKey, TValue>>();
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
{
list.Add(kvp);
}
return list.ToArray();
}
public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value = default(TValue))
{
if (dictionary.ContainsKey(key))
{
return dictionary[key];
}
return value;
}
#endregion
#region Arrays
public static void Fill<T>(this T[] data, T value)
{
for (int i = 0; i < data.Length; i++)
{
data[i] = value;
}
}
#endregion
public static long RoundToNearestPowerOf2(this long input)
{
long v = input;
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
[CLSCompliant(false)]
public static ulong RoundToNearestPowerOf2(this ulong input)
{
ulong v = input;
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
}
}