using System; using System.Collections.Generic; using System.Linq; using System.Net.Mail; using System.Text.RegularExpressions; namespace ErrorsManager{ // public abstract record Error{ // private Error(){} // public sealed record String(string value):Error; // public sealed record Array(byte[] value):Error; // public sealed record Integer(int value):Error; // } class ErrorsManager{ public static readonly char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".ToCharArray(); public static readonly Regex RE_KEY = new Regex(@"^[a-z_][a-z0-9_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private Error error = 0; private char[] alphabet; private Dictionary dictionary = new Dictionary(); private byte _base; private byte power; public ErrorsManager(object? inputs = null){ set_alphabet(get("alphabet", inputs, ALPHABET)); } public int set_alphabet(object? alphabet = null){ int original_length; error = 0; if(alphabet == null) this.alphabet = ALPHABET; else if(alphabet is string alphabet_string) this.alphabet = alphabet_string.ToCharArray(); else if(alphabet is IEnumerable alphabet_enumerable) this.alphabet = alphabet_enumerable.ToArray(); else{ error |= 1 << 2; this.alphabet = ALPHABET; } original_length = this.alphabet.Length; this.alphabet = this.alphabet.Distinct().ToArray(); if(this.alphabet.Length < 2){ error |= 1 << 3; this.alphabet = ALPHABET; } if(this.alphabet.Length != original_length) error |= 1 << 4; if(this.alphabet.Length > 128) error |= 1 << 5; this.alphabet = this.alphabet.Take( _base = (byte)Math.Pow(2, power = (byte)Math.Log2(this.alphabet.Length) ) ).ToArray(); dictionary.Clear(); for(byte i = 0; i < this.alphabet.Length; i ++) dictionary[this.alphabet[i]] = i; return error; } public string get_alphabet(){ return new string(alphabet); } public byte[] to_array(object code){ if(code is string _string) return _string.Select(character => dictionary[character]).ToArray(); if(code is byte[] array) return array; if(code is int integer){ List hexas = new List(); while(integer != 0){ hexas.Add((byte)(integer % _base)); integer /= _base; } return hexas.ToArray(); } return new byte[]{}; } public string to_string(object code){ if(code is string _string) return _string; if(code is byte[] array) return new string(array.Select(value => alphabet[value]).ToArray()); if(code is int integer){ string hexas = new string(); while(integer != 0){ hexas += alphabet[(byte)(integer % _base)]; integer /= _base; } return hexas; } return ""; } public int to_integer(object code){ if(code is string _string){ int integer = 0; for(byte i = 0; i < _string.Length; i ++) integer = integer * _base + dictionary[_string[i]]; return integer; } if(code is byte[] array){ int integer = 0; for(byte i = 0; i < array.Length; i ++) integer = integer * _base + array[i]; return integer; } if(code is int integer) return integer; return 0; } public (int, string)[] process(Error code, IEnumerable messages){ List<(int, string)> response = new List<(int, string)>(); for_each_enumerate(get_hexas_from(code), (hexa, i) => { for(byte j = 0; j < power && (hexa & 1 << j) <= hexa; j ++) if((hexa & 1 << j) != 0){ int x = i * power + j; response.Add((x, messages.ElementAtOrDefault(x) ?? "error_message_" + x.ToString())); } }); return response.ToArray(); } public int get_bits(object code){ if(code is string _string) return _string.Length == 0 ? 0 : (_string.Length - 1) * power + (int)Math.Ceiling(Math.Log2(dictionary[_string.Last()] + 1)); if(code is byte[] array) return array.Length == 0 ? 0 : (array.Length - 1) * power + (int)Math.Ceiling(Math.Log2(array.Last() + 1)); if(code is int integer) return (int)Math.Ceiling(Math.Log2(integer + 1)); return 0; } public T bitwise(T code, int bits){ if(code is string _string) return (T)(object)to_string(bitwise(to_array(_string), bits)); if(code is byte[] array){ byte shift; int mask; List hexas; if(bits < 0){ if(array.Length < (int)((bits *= -1) / power)) return (T)(object)new byte[]{0}; shift = (byte)(bits % power); mask = _base - 1; hexas = array.ToList(); hexas.RemoveRange(0, (int)(bits / power)); if(shift != 0 && hexas.Count != 0){ int l = hexas.Count - 1; for(int i = 0; i < l; i ++) hexas[i] = (byte)((hexas[i] >> shift) | ((hexas[i + 1] << (power - shift)) & mask)); hexas[hexas.Count - 1] >>= shift; } return (T)(object)hexas.ToArray(); }; if(bits > 0){ shift = (byte)(bits % power); mask = _base - 1; hexas = array.ToList(); if(shift != 0){ int last_hexa = hexas[hexas.Count - 1] << shift; for(int i = hexas.Count - 1; i > 0; i --) hexas[i] = (byte)((hexas[i] << shift) | ((hexas[i - 1] >> (power - shift)) & mask)); hexas[0] = (byte)((hexas[0] << shift) & mask); if(last_hexa >= _base) hexas.Add((byte)(last_hexa >> power)); } for(int i = bits / power; i > 0; i --) hexas.Insert(0, 0); return (T)(object)hexas.ToArray(); } return (T)(object)array; } if(code is int integer) return (T)(object)( bits > 0 ? integer << bits : bits < 0 ? integer >> -bits : integer); return code; } public void get_from_bits(object code, ref int from, ref int bits){ if(from < 0){ from = get_bits(code) + from; if(from < 0) from = 0; } if(bits < 0){ from += bits; bits *= -1; if(from < 0){ bits += from; from = 0; } } } public T reset(T code, int from, int bits = 0, bool reversed = false){ if(bits == 0 || (from == 0 && bits < 0)) return code; if(code is string _string) return (T)(object)to_string(reset(to_array(_string), from, bits, reversed)); if(code is byte[] array){ List hexas = array.ToList(); int hexa_from; int hexa_to; int l; byte from_mask; byte to_mask; get_from_bits(array, ref from, ref bits); hexa_from = (int)(from / power); hexa_to = (int)((from + bits) / power); if(reversed){ l = from % power; from_mask = (byte)(~-(1 << power - l) << l); to_mask = (byte)~-(1 << (from + bits) % power); for(int i = 0; i < hexas.Count; i ++) if(i < hexa_from || i > hexa_to) hexas[i] = 0; if(hexa_from == hexa_to) hexas[hexa_to] &= (byte)(from_mask & to_mask); else{ hexas[hexa_from] &= from_mask; if(hexa_to < hexas.Count) hexas[hexa_to] &= to_mask; } }else{ l = (from + bits) % power; from_mask = (byte)~-(1 << (from % power)); to_mask = (byte)(~-(1 << power - l) << l); if(hexa_from == hexa_to){ hexas[hexa_to] &= (byte)(from_mask | to_mask); }else{ hexas[hexa_from] &= from_mask; for(int i = hexa_from + 1; i < hexa_to && i < hexas.Count; i ++) hexas[i] = 0; if(hexa_to < hexas.Count) hexas[hexa_to] &= to_mask; } } return (T)(object)hexas.ToArray(); } if(code is int integer){ get_from_bits(integer, ref from, ref bits); return (T)(object)(integer & (reversed ? ~-(1 << bits) << from : (~-(1 << get_bits(integer)) << from + bits) | ~-(1 << from))); } return code; } public T get_range(T code, int from, int length = 0){ if(code is string _string) return to_string(get_range(to_array(_string), length)); if(code is byte[] array){ List hexas = new List(); if(from > 0){ byte shift = (byte)(from % power); int mask = ~-_base; hexas.AddRange(array.Take(from / power)); if(shift != 0){ for(int i = hexas.Count - 2; i >= 0; i --) hexas[i] = (byte)((hexas[i] >> shift) | ((hexas[i + 1] << (power - shift)) & mask)); hexas[hexas.Count - 1] = (byte)(hexas.Last() >> shift); } } if(length > 0){ byte shift = (byte)(length % power); hexas.Take((int)Math.Ceiling(hexas.Count / (double)power)); if(shift != 0) hexas[hexas.Count - 1] = (byte)(hexas.Last() & ~-(1 << shift)); } return to_integer(array.Skip(from / power).Take((int)Math.Ceiling((length != 0 ? length : get_bits(array) - from) / (double)power)).ToArray()); } if(code is int integer) return (from > 0 ? integer >> from : integer) & (length > 0 ? ~(-1 << length) : integer); return code; } public bool has(Error code, int? bits = null){ return code switch{ Error.String _string => _string.value.ToList().Take(get_hexas_from_bits(bits)).Length * power > bits, Error.Array array => array.value.ToList().Take(Math.Ceiling(Math.Log2(bits))).Where(hexa => hexa != 0).Count() != 0, Error.Integer integer => (bits != null && bits != 0 ? ~-(1 << bits) & integer.value : integer.value) != 0, _ => false }; } public static List get_keys(object? items){ List keys = new List(); if(items is string item_string){ if(RE_KEY.IsMatch(item_string)) keys.Add(item_string); }else if(items is IEnumerable strings){ foreach(string item_i in strings) if(!keys.Contains(item_i) && RE_KEY.IsMatch(item_i)) keys.Add(item_i); }else if(items is IEnumerable list) foreach(object? item in list){ if(item == null) continue; if(item is string string_item){ if(!keys.Contains(string_item) && RE_KEY.IsMatch(string_item)) keys.Add(string_item); }else foreach(string key in get_keys(item)) if(!keys.Contains(key) && RE_KEY.IsMatch(key)) keys.Add(key); } return keys; } public static List> get_dictionaries(object? items){ List> dictionaries = new List>(); if(items is Dictionary dictionary) dictionaries.Add(dictionary); else if(items is IEnumerable list) foreach(object? item in list) dictionaries.AddRange(get_dictionaries(item)); return dictionaries; } public static T? get(object keys, object? dictionaries, T? _default = default(T?)){ List keys_list = get_keys(keys); if(keys_list.Count != 0) foreach(Dictionary dictionary in get_dictionaries(dictionaries)) foreach(string key in keys_list) if(dictionary.TryGetValue(key, out object? value) && value is T typed) return typed; return _default; } public static T[] unique(IEnumerable items){ return items.Distinct().ToArray(); } public static bool is_string(object value){ return value is string; } public static bool is_array(object value){ return value is byte[]; } public static bool is_integer(object value){ return value is int; } public static void for_each_enumerate(IEnumerable items, Action action){ int i = 0; foreach(T item in items) action(item, i ++); } } }