using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; namespace ErrorsManager{ public class ErrorsManager{ public static readonly char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".ToCharArray(); public static readonly string[] ERRORS_MESSAGES = new string[]{ "invalid_alphabet", "invalid_base", "invalid_alphabet_type", "too_short_alphabet", "repeated_characters_in_alphabet", "too_long_alphabet", "base_lower_than_2", "base_greater_than_128", "base_greater_than_alphabet" }; public static readonly Regex RE_KEY = new Regex(@"^[a-z_][a-z0-9_]*$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private int error = 0; private char[] alphabet = new char[0]; private Dictionary dictionary = new Dictionary(); private byte _base; private byte power; public ErrorsManager(object inputs = null){ set_alphabet( get("alphabet", inputs, ALPHABET), get("base", inputs, 64) ); } public int set_alphabet(object alphabet = null, int _base = 64){ 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; error |= ( _base < 2 ? 1 << 0 : _base > 128 ? 1 << 1 : _base >= this.alphabet.Length ? 1 << 2 : 0) << 6; if(error >> 6 == 0) this.alphabet = this.alphabet.Take(_base).ToArray(); this.alphabet = this.alphabet.Take( this._base = (byte)Math.Pow(2, power = (byte)Math.Log2(this.alphabet.Take(128).Count()) ) ).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(string code){ return code.Select(character => dictionary[character]).ToArray(); } public byte[] to_array(byte[] code){ return code; } public byte[] to_array(int code){ List hexas = new List(); while(code != 0){ hexas.Add((byte)(code % _base)); code /= _base; } return hexas.ToArray(); } public string to_string(byte[] code){ return new string(code.Select(value => alphabet[value]).ToArray()); } public string to_string(int code){ string hexas = ""; while(code != 0){ hexas += alphabet[(byte)(code % _base)]; code /= _base; } return hexas; } public string to_string(string code){ return code; } public int to_integer(string code){ int _string = 0; for(int i = code.Length - 1; i >= 0; i --) _string = _string * _base + dictionary[code[i]]; return _string; } public int to_integer(byte[] code){ int array = 0; for(int i = code.Length - 1; i >= 0; i --) array = array * _base + code[i]; return array; } public int to_integer(int code){ return code; } public string to_string_binary(string code){ return string.Join("", code.Reverse().Select(character => Convert.ToString(dictionary[character], 2).PadLeft(power, '0'))); } public string to_string_binary(byte[] code){ return string.Join("", code.Reverse().Select(hexa => Convert.ToString(hexa, 2).PadLeft(power, '0'))); } public string to_string_binary(int code){ string binary = Convert.ToString(code, 2); int remainer = binary.Length % power; return ( remainer == 0 ? binary : binary.PadLeft(binary.Length + power - remainer, '0')); } public (int, string)[] process(string code, IEnumerable messages){ return process(to_array(code), messages); } public (int, string)[] process(byte[] code, IEnumerable messages){ List<(int, string)> response = new List<(int, string)>(); for_each_enumerate(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, string)[] process(int code, IEnumerable messages){ return process(to_array(code), messages); } public int get_bits(string code){ return code.Length == 0 ? 0 : (code.Length - 1) * power + (int)Math.Ceiling(Math.Log2(dictionary[code.Last()] + 1)); } public int get_bits(byte[] code){ return code.Length == 0 ? 0 : (code.Length - 1) * power + (int)Math.Ceiling(Math.Log2(code.Last() + 1)); } public int get_bits(int code){ return (int)Math.Ceiling(Math.Log2(code + 1)); } public string clean(string code){ int l = code.Length; while(l > 0 && code[l - 1] == alphabet[0]) l --; return ( code.Length == l ? code : l == 0 ? alphabet[0].ToString() : code.Substring(0, l)); } public byte[] clean(byte[] code){ int l = code.Length; while(l > 0 && code[l - 1] == 0) l --; return ( l == code.Length ? code : l == 0 ? new byte[]{0} : code.Take(l).ToArray()); } public int clean(int code){ return code; } public string bitwise(string code, int bits){ return to_string(bitwise(to_array(code), bits)); } public byte[] bitwise(byte[] code, int bits){ if(code.Length == 0 || bits == 0) return code; byte shift = (byte)(Math.Abs(bits) % power); int mask = _base - 1; List hexas = code.ToList(); if(bits < 0){ 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; } }else{ 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) & mask) | (hexas[i - 1] >> (power - shift))); 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 clean(hexas.ToArray()); } public int bitwise(int code, int bits){ return ( bits > 0 ? code << bits : bits < 0 ? code >> -bits : code); } public void get_from_bits(string code, ref int from, ref int bits){ get_from_bits(to_array(code), ref from, ref bits); } public void get_from_bits(byte[] 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 void get_from_bits(int code, ref int from, ref int bits){ get_from_bits(to_array(code), ref from, ref bits); } public string reset(string code, int from, int bits = 0, bool reversed = false){ return to_string(reset(to_array(code), from, bits, reversed)); } public byte[] reset(byte[] code, int from, int bits = 0, bool reversed = false){ List hexas = code.ToList(); int hexa_from; int hexa_to; int l; byte from_mask; byte to_mask; get_from_bits(code, 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 hexas.ToArray(); } public int reset(int code, int from, int bits = 0, bool reversed = false){ get_from_bits(code, ref from, ref bits); if(from + bits > 31) bits = 31 - from; return code & (reversed ? ~-(1 << bits) << from : (~-(1 << get_bits(code)) << from + bits) | ~-(1 << from)); } public string get_range(string code, int from, int bits = 0){ return to_string(get_range(to_array(code), from, bits)); } public byte[] get_range(byte[] code, int from, int bits = 0){ List hexas; get_from_bits(code, ref from, ref bits); if(bits == 0) bits = get_bits(code) - from; if(bits <= 0) return new byte[]{0}; hexas = code.ToList(); if(from > 0){ byte shift = (byte)(from % power); int mask = ~-_base; hexas = hexas.Skip(from / power).ToList(); 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; } } if(bits > 0){ byte shift = (byte)(bits % power); hexas = hexas.Take((int)Math.Ceiling(bits / (double)power)).ToList(); if(shift != 0 && hexas.Count > 0) hexas[hexas.Count - 1] &= (byte)((1 << shift) - 1); } return clean(hexas.ToArray()); } public int get_range(int code, int from, int bits = 0){ get_from_bits(code, ref from, ref bits); if(from > 0) code = (code >> from) & ((1 << (31 - from)) - 1); if(bits <= 0 || bits >= 31) return code; if(from + bits > 31) bits = 31 - from; return code & ((1 << bits) - 1); } public bool has(string code, int from = 0, int bits = 0){ foreach(char character in get_range(code, from, bits)) if(character != alphabet[0]) return true; return false; } public bool has(byte[] code, int from = 0, int bits = 0){ foreach(byte hexa in get_range(code, from, bits)) if(hexa != 0) return true; return false; } public bool has(int code, int from = 0, int bits = 0){ return get_range(code, from, bits) != 0; } public string set(string error, string code, int _from = 0, int bits = 0){ return to_string(set(to_array(error), to_array(code), _from, bits)); } public string set(string error, byte[] code, int _from = 0, int bits = 0){ return to_string(set(to_array(error), code, _from, bits)); } public string set(string error, int code, int _from = 0, int bits = 0){ return to_string(set(to_array(error), to_array(code), _from, bits)); } public byte[] set(byte[] error, string code, int _from = 0, int bits = 0){ return set(error, to_array(code), _from, bits); } public byte[] set(byte[] error, byte[] code, int _from = 0, int bits = 0){ int l; int m = error.Length; int n = code.Length; List results = new List(); if(bits != 0) error = reset(error, _from, bits); if(_from != 0) n = (code = bitwise(code, _from)).Length; l = m > n ? m : n; for(int i = 0; i < l; i ++) results.Add((byte)( (i < m ? error[i] : (byte)0) | (i < n ? code[i] : (byte)0) )); return clean(results.ToArray()); } public byte[] set(byte[] error, int code, int _from = 0, int bits = 0){ return set(error, to_array(code), _from, bits); } public int set(int error, string code, int _from = 0, int bits = 0){ return to_integer(set(error, to_integer(code), _from, bits)); } public int set(int error, byte[] code, int _from = 0, int bits = 0){ return to_integer(set(error, to_integer(code), _from, bits)); } public int set(int error, int code, int _from = 0, int bits = 0){ if(bits != 0) error = reset(error, _from, bits); if(_from != 0) code = bitwise(code, _from); return error | code; } 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 ++); } } }