444 lines
15 KiB
C#
444 lines
15 KiB
C#
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<char, byte> dictionary = new Dictionary<char, byte>();
|
|
private byte _base;
|
|
private byte power;
|
|
|
|
public ErrorsManager(object? inputs = null){
|
|
|
|
set_alphabet(get<object?>("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<char> alphabet_enumerable)
|
|
this.alphabet = alphabet_enumerable.ToArray<char>();
|
|
else{
|
|
error |= 1 << 2;
|
|
this.alphabet = ALPHABET;
|
|
}
|
|
|
|
original_length = this.alphabet.Length;
|
|
|
|
this.alphabet = this.alphabet.Distinct<char>().ToArray<char>();
|
|
|
|
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<char>();
|
|
|
|
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<char, byte>(character => dictionary[character]).ToArray<byte>();
|
|
if(code is byte[] array)
|
|
return array;
|
|
if(code is int integer){
|
|
|
|
List<byte> hexas = new List<byte>();
|
|
|
|
while(integer != 0){
|
|
hexas.Add((byte)(integer % _base));
|
|
integer /= _base;
|
|
}
|
|
|
|
return hexas.ToArray<byte>();
|
|
}
|
|
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<byte, char>(value => alphabet[value]).ToArray<char>());
|
|
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<string> 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<char>()] + 1));
|
|
if(code is byte[] array)
|
|
return array.Length == 0 ? 0 : (array.Length - 1) * power + (int)Math.Ceiling(Math.Log2(array.Last<byte>() + 1));
|
|
if(code is int integer)
|
|
return (int)Math.Ceiling(Math.Log2(integer + 1));
|
|
return 0;
|
|
}
|
|
|
|
public T bitwise<T>(T code, int bits){
|
|
if(code is string _string)
|
|
return (T)(object)to_string(bitwise<byte[]>(to_array(_string), bits));
|
|
if(code is byte[] array){
|
|
|
|
byte shift;
|
|
int mask;
|
|
List<byte> 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<byte>();
|
|
|
|
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<byte>();
|
|
};
|
|
if(bits > 0){
|
|
|
|
shift = (byte)(bits % power);
|
|
mask = _base - 1;
|
|
hexas = array.ToList<byte>();
|
|
|
|
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<byte>();
|
|
}
|
|
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>(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<byte[]>(to_array(_string), from, bits, reversed));
|
|
if(code is byte[] array){
|
|
|
|
List<byte> hexas = array.ToList<byte>();
|
|
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<byte>();
|
|
}
|
|
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>(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<byte> hexas = new List<byte>();
|
|
|
|
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<byte>() >> shift);
|
|
}
|
|
|
|
}
|
|
if(length > 0){
|
|
|
|
byte shift = (byte)(length % power);
|
|
|
|
hexas.Take<byte>((int)Math.Ceiling(hexas.Count / (double)power));
|
|
if(shift != 0)
|
|
hexas[hexas.Count - 1] = (byte)(hexas.Last<byte>() & ~-(1 << shift));
|
|
}
|
|
|
|
return to_integer(array.Skip(from / power).Take((int)Math.Ceiling((length != 0 ? length : get_bits(array) - from) / (double)power)).ToArray<byte>());
|
|
}
|
|
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<char>().Take<byte>(get_hexas_from_bits(bits)).Length * power > bits,
|
|
Error.Array array => array.value.ToList<byte>().Take<byte>(Math.Ceiling(Math.Log2(bits))).Where<byte>(hexa => hexa != 0).Count<byte>() != 0,
|
|
Error.Integer integer => (bits != null && bits != 0 ? ~-(1 << bits) & integer.value : integer.value) != 0,
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
public static List<string> get_keys(object? items){
|
|
|
|
List<string> keys = new List<string>();
|
|
|
|
if(items is string item_string){
|
|
if(RE_KEY.IsMatch(item_string))
|
|
keys.Add(item_string);
|
|
}else if(items is IEnumerable<string> 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<object?> 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<Dictionary<string, object?>> get_dictionaries(object? items){
|
|
|
|
List<Dictionary<string, object?>> dictionaries = new List<Dictionary<string, object?>>();
|
|
|
|
if(items is Dictionary<string, object?> dictionary)
|
|
dictionaries.Add(dictionary);
|
|
else if(items is IEnumerable<object?> list)
|
|
foreach(object? item in list)
|
|
dictionaries.AddRange(get_dictionaries(item));
|
|
|
|
return dictionaries;
|
|
}
|
|
|
|
public static T? get<T>(object keys, object? dictionaries, T? _default = default(T?)){
|
|
|
|
List<string> keys_list = get_keys(keys);
|
|
|
|
if(keys_list.Count != 0)
|
|
foreach(Dictionary<string, object?> 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<T>(IEnumerable<T> items){
|
|
return items.Distinct<T>().ToArray<T>();
|
|
}
|
|
|
|
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<T>(IEnumerable<T> items, Action<T, int> action){
|
|
|
|
int i = 0;
|
|
|
|
foreach(T item in items)
|
|
action(item, i ++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |