629 lines
20 KiB
C#
629 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
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<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),
|
|
get<int>("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<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;
|
|
|
|
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<char>();
|
|
|
|
this.alphabet = this.alphabet.Take(
|
|
this._base = (byte)Math.Pow(2,
|
|
power = (byte)Math.Log2(this.alphabet.Take(128).Count<char>())
|
|
)
|
|
).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(string code){
|
|
return code.Select<char, byte>(character => dictionary[character]).ToArray<byte>();
|
|
}
|
|
|
|
public byte[] to_array(byte[] code){
|
|
return code;
|
|
}
|
|
|
|
public byte[] to_array(int code){
|
|
|
|
List<byte> hexas = new List<byte>();
|
|
|
|
while(code != 0){
|
|
hexas.Add((byte)(code % _base));
|
|
code /= _base;
|
|
}
|
|
|
|
return hexas.ToArray<byte>();
|
|
}
|
|
|
|
public string to_string(byte[] code){
|
|
return new string(code.Select<byte, char>(value => alphabet[value]).ToArray<char>());
|
|
}
|
|
|
|
public string to_string(int code){
|
|
|
|
StringBuilder hexas = new StringBuilder();
|
|
|
|
while(code != 0){
|
|
hexas.Append(alphabet[(byte)(code % _base)]);
|
|
code /= _base;
|
|
}
|
|
|
|
return hexas.ToString();
|
|
}
|
|
|
|
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<char>().Select<char, string>(character => Convert.ToString(dictionary[character], 2).PadLeft(power, '0')));
|
|
}
|
|
|
|
public string to_string_binary(byte[] code){
|
|
return string.Join("", code.Reverse<byte>().Select<byte, string>(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 get_bits(string code){
|
|
return code.Length == 0 ? 0 : (code.Length - 1) * power + (int)Math.Ceiling(Math.Log2(dictionary[code.Last<char>()] + 1));
|
|
}
|
|
|
|
public int get_bits(byte[] code){
|
|
return code.Length == 0 ? 0 : (code.Length - 1) * power + (int)Math.Ceiling(Math.Log2(code.Last<byte>() + 1));
|
|
}
|
|
|
|
public int get_bits(int code){
|
|
return (int)Math.Ceiling(Math.Log2(code + 1));
|
|
}
|
|
|
|
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 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<byte>());
|
|
}
|
|
|
|
public int clean(int code){
|
|
return code;
|
|
}
|
|
|
|
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<byte> 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<byte>();
|
|
|
|
if(from > 0){
|
|
|
|
byte shift = (byte)(from % power);
|
|
int mask = ~-_base;
|
|
|
|
hexas = hexas.Skip(from / power).ToList<byte>();
|
|
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[l] >>= shift;
|
|
|
|
}
|
|
|
|
}
|
|
if(bits > 0){
|
|
|
|
byte shift = (byte)(bits % power);
|
|
|
|
hexas = hexas.Take<byte>((int)Math.Ceiling(bits / (double)power)).ToList<byte>();
|
|
if(shift != 0 && hexas.Count > 0)
|
|
hexas[hexas.Count - 1] &= (byte)((1 << shift) - 1);
|
|
|
|
}
|
|
|
|
return clean(hexas.ToArray<byte>());
|
|
}
|
|
|
|
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 (int, string)[] process(string code, IEnumerable<string> messages){
|
|
return process(to_array(code), messages);
|
|
}
|
|
|
|
public (int, string)[] process(byte[] code, IEnumerable<string> messages, Dictionary<int, int>? blocks = null){
|
|
|
|
List<(int, string)> response = new List<(int, string)>();
|
|
int k = 0;
|
|
|
|
if(blocks == null)
|
|
blocks = new Dictionary<int, int>();
|
|
|
|
for(int i = 0, l = code.Length * power; i < l;)
|
|
if(blocks.ContainsKey(i) && blocks[i] > 0){
|
|
|
|
int logarithm = (int)Math.Ceiling(Math.Log2(blocks[i]));
|
|
int _k = to_integer(get_range(code, i, logarithm == 0 ? logarithm = 1 : logarithm));
|
|
|
|
if(_k > 0){
|
|
_k = k + _k;
|
|
response.Add((_k, messages.ElementAtOrDefault(_k) ?? "error_message_" + _k.ToString()));
|
|
}
|
|
|
|
k += blocks[i];
|
|
i += logarithm;
|
|
|
|
}else{
|
|
if((code[i / power] & (1 << i % power)) != 0)
|
|
response.Add((k, messages.ElementAtOrDefault(k) ?? "error_message_" + k.ToString()));
|
|
k ++;
|
|
i ++;
|
|
}
|
|
|
|
return response.ToArray<(int, string)>();
|
|
}
|
|
|
|
public (int, string)[] process(int code, IEnumerable<string> messages){
|
|
return process(to_array(code), messages);
|
|
}
|
|
|
|
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<byte> hexas = code.ToList<byte>();
|
|
|
|
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) | (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 clean(hexas.ToArray<byte>());
|
|
}
|
|
|
|
public int bitwise(int code, int bits){
|
|
return (
|
|
bits > 0 ? code << bits :
|
|
bits < 0 ? code >> -bits :
|
|
code);
|
|
}
|
|
|
|
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<byte> hexas = code.ToList<byte>();
|
|
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 clean(hexas.ToArray<byte>());
|
|
}
|
|
|
|
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 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<byte> results = new List<byte>();
|
|
|
|
if(bits != 0)
|
|
m = (error = reset(error, _from, bits)).Length;
|
|
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<byte>());
|
|
}
|
|
|
|
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<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 inputs, T _default = default(T)){
|
|
|
|
List<string> keys_list = get_keys(keys);
|
|
|
|
if(keys_list.Count != 0)
|
|
foreach(Dictionary<string, object> dictionary in get_dictionaries(inputs))
|
|
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 ++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |