Created
December 17, 2018 07:53
-
-
Save mjs3339/d2ced08824903b827d7cdbe91cfe98b4 to your computer and use it in GitHub Desktop.
C# ByteArray Class Manages an Array of Bytes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ByteArray : IFormattable, IComparable, IComparable<ByteArray>, IEquatable<ByteArray> | |
{ | |
public byte[] bytes; | |
public ByteArray() : this(0) | |
{ | |
} | |
public ByteArray(int size) | |
{ | |
bytes = new byte[size]; | |
Active = true; | |
} | |
public ByteArray(byte[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(string str) | |
{ | |
var ba = str.GetBytes(); | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(string str, int size = 0) | |
{ | |
var ba = str.GetBytes(); | |
if(size > ba.Length) | |
throw new Exception("Size exceeds buffer length."); | |
if(size == 0) | |
size = ba.Length; | |
bytes = new byte[size]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, size); | |
Active = true; | |
} | |
public ByteArray(sbyte[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(short[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(ushort[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(int[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(uint[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(long[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(ulong[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(decimal[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(float[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public ByteArray(double[] ba) | |
{ | |
bytes = new byte[ba.Length]; | |
Buffer.BlockCopy(ba, 0, bytes, 0, ba.Length); | |
Active = true; | |
} | |
public int Length => bytes.Length; | |
public bool Active {get; set;} | |
public byte this[int index] | |
{ | |
get | |
{ | |
if(index > bytes.Length) | |
throw new Exception("Error: Index out of range."); | |
return bytes[index]; | |
} | |
set | |
{ | |
if(index > bytes.Length) | |
throw new Exception("Error: Index out of range."); | |
bytes[index] = value; | |
} | |
} | |
public int CompareTo(object obj) | |
{ | |
throw new NotImplementedException(); | |
} | |
public int CompareTo(ByteArray other) | |
{ | |
throw new NotImplementedException(); | |
} | |
public bool Equals(ByteArray other) | |
{ | |
if(bytes == null && other.bytes == null) | |
return true; | |
if(bytes != null && other.bytes == null) | |
return false; | |
if(bytes == null && other.bytes != null) | |
return false; | |
if(bytes == null) | |
return false; | |
if(other.bytes == null) | |
return false; | |
return Compare(bytes, other.bytes); | |
} | |
public string ToString(string format, IFormatProvider formatProvider) | |
{ | |
throw new NotImplementedException(); | |
} | |
public static explicit operator byte(ByteArray value) | |
{ | |
return checked((byte) (long) value); | |
} | |
public static explicit operator sbyte(ByteArray value) | |
{ | |
return checked((sbyte) (long) value); | |
} | |
public static explicit operator short(ByteArray value) | |
{ | |
return checked((short) (long) value); | |
} | |
public static explicit operator ushort(ByteArray value) | |
{ | |
return checked((ushort) (long) value); | |
} | |
public static explicit operator int(ByteArray value) | |
{ | |
return checked((int) (long) value); | |
} | |
public static explicit operator uint(ByteArray value) | |
{ | |
return checked((uint) (long) value); | |
} | |
public static explicit operator long(ByteArray value) | |
{ | |
return ToIntAny(value.bytes, 0); | |
} | |
public static explicit operator ulong(ByteArray value) | |
{ | |
return checked((ulong) (long) value); | |
} | |
public static explicit operator decimal(ByteArray value) | |
{ | |
return(long) value; | |
} | |
public static explicit operator float(ByteArray value) | |
{ | |
return(long) value; | |
} | |
public static explicit operator double(ByteArray value) | |
{ | |
return(ulong) value; | |
} | |
[SecuritySafeCritical] | |
private static unsafe long ToIntAny(byte[] value, int startIndex) | |
{ | |
if(value == null) | |
throw new Exception("Error: Value cannot be null."); | |
if((uint) startIndex >= value.Length) | |
throw new Exception("Error: StartIndex cannot be greater than or equal to the length of value."); | |
fixed(byte* pbyte = &value[startIndex]) | |
{ | |
if(value.Length == 8) | |
{ | |
if(startIndex % 8 == 0) | |
return*(long*) pbyte; | |
var i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | *(pbyte + 3); | |
var i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | *(pbyte + 7); | |
return(uint) i2 | ((long) i1 << 32); | |
} | |
if(value.Length == 4) | |
{ | |
if(startIndex % 4 == 0) | |
return*(int*) pbyte; | |
return(*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | *(pbyte + 3); | |
} | |
if(value.Length == 2) | |
{ | |
if(startIndex % 2 == 0) | |
return*(short*) pbyte; | |
return(short) ((*pbyte << 8) | *(pbyte + 1)); | |
} | |
if(value.Length == 1) | |
return*(char*) pbyte; | |
} | |
return-1; | |
} | |
public static ByteArray operator +(ByteArray a, ByteArray b) | |
{ | |
return Add(a.bytes, b.bytes); | |
} | |
public static ByteArray operator +(ByteArray a, byte[] b) | |
{ | |
return Add(a.bytes, b); | |
} | |
public static ByteArray operator +(ByteArray a, byte b) | |
{ | |
return Add(a.bytes, new[] {b}); | |
} | |
public static ByteArray operator +(ByteArray a) | |
{ | |
return a; | |
} | |
public static bool operator ==(ByteArray a, ByteArray b) | |
{ | |
return a.Equals(b); | |
} | |
public static bool operator !=(ByteArray a, ByteArray b) | |
{ | |
return!a.Equals(b); | |
} | |
public static ByteArray operator &(ByteArray a, ByteArray b) | |
{ | |
return And(a.bytes, b.bytes); | |
} | |
public static ByteArray operator |(ByteArray a, ByteArray b) | |
{ | |
return Or(a.bytes, b.bytes); | |
} | |
public static ByteArray operator ^(ByteArray a, ByteArray b) | |
{ | |
return Xor(a.bytes, b.bytes); | |
} | |
public static ByteArray operator ~(ByteArray a) | |
{ | |
return Not(a.bytes); | |
} | |
public static ByteArray operator -(ByteArray a) | |
{ | |
return Neg(a.bytes); | |
} | |
public static ByteArray operator %(ByteArray a, ByteArray b) | |
{ | |
return Mod(a.bytes, b.bytes); | |
} | |
public static ByteArray operator *(ByteArray a, ByteArray b) | |
{ | |
return Mul(a.bytes, b.bytes); | |
} | |
public static ByteArray operator /(ByteArray a, ByteArray b) | |
{ | |
return Div(a.bytes, b.bytes); | |
} | |
public static ByteArray operator <<(ByteArray a, int shift) | |
{ | |
if(shift > a.Length) | |
return new ByteArray(a.Length); | |
var t = new byte[a.Length]; | |
for(var i = 0; i < a.Length - shift; ++i) | |
t[i] = a[i + shift]; | |
return new ByteArray(t); | |
} | |
public static ByteArray operator >>(ByteArray a, int shift) | |
{ | |
if(shift > a.Length) | |
return new ByteArray(a.Length); | |
var t = new byte[a.Length]; | |
for(int i = shift, ptr = 0; i < a.Length; ++i, ptr++) | |
t[ptr] = a[i]; | |
return new ByteArray(t); | |
} | |
private static ByteArray Div(byte[] left, byte[] right) | |
{ | |
var l1 = left.Length; | |
var l2 = right.Length; | |
if(l1 != l2) | |
throw new Exception("Error: left and right arrays lengths must be equal."); | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((left[i] / right[i]) & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Mul(byte[] left, byte[] right) | |
{ | |
var l1 = left.Length; | |
var l2 = right.Length; | |
if(l1 != l2) | |
throw new Exception("Error: left and right arrays lengths must be equal."); | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((left[i] * right[i]) & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Mod(byte[] left, byte[] right) | |
{ | |
var l1 = left.Length; | |
var l2 = right.Length; | |
if(l1 != l2) | |
throw new Exception("Error: left and right arrays lengths must be equal."); | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((left[i] % right[i]) & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Neg(byte[] left) | |
{ | |
var l1 = left.Length; | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((short) -left[i] & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Not(byte[] left) | |
{ | |
var l1 = left.Length; | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((ushort) ~left[i] & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Xor(byte[] left, byte[] right) | |
{ | |
var l1 = left.Length; | |
var l2 = right.Length; | |
if(l1 != l2) | |
throw new Exception("Error: left and right arrays lengths must be equal."); | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((left[i] ^ right[i]) & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Or(byte[] left, byte[] right) | |
{ | |
var l1 = left.Length; | |
var l2 = right.Length; | |
if(l1 != l2) | |
throw new Exception("Error: left and right arrays lengths must be equal."); | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) ((left[i] | right[i]) & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray And(byte[] left, byte[] right) | |
{ | |
var l1 = left.Length; | |
var l2 = right.Length; | |
if(l1 != l2) | |
throw new Exception("Error: left and right arrays lengths must be equal."); | |
var ret = new byte[l1]; | |
for(var i = 0; i < l1; ++i) | |
ret[i] = (byte) (left[i] & right[i] & 0xff); | |
return new ByteArray(ret); | |
} | |
private static ByteArray Add(byte[] left, byte[] right) | |
{ | |
var ab = left.ConcatEx(right); | |
if(right == null) | |
throw new Exception("Right side must not be null."); | |
if(left == null) | |
{ | |
left = new byte[right.Length]; | |
Buffer.BlockCopy(right, 0, left, 0, right.Length); | |
return new ByteArray(left); | |
; | |
} | |
var l1 = left.Length; | |
var l2 = right.Length; | |
var ret = new byte[l1 + l2]; | |
Buffer.BlockCopy(left, 0, ret, 0, l1); | |
Buffer.BlockCopy(right, 0, ret, l1, l2); | |
return new ByteArray(ret); | |
} | |
public override string ToString() | |
{ | |
var sb = new StringBuilder(); | |
foreach(var b in bytes) | |
{ | |
var hex = b.ToString("X2"); | |
sb.Append(hex); | |
} | |
return sb.ToString(); | |
} | |
public override bool Equals(object obj) | |
{ | |
if(ReferenceEquals(null, obj)) return false; | |
return obj is ByteArray && Equals((ByteArray) obj); | |
} | |
public override int GetHashCode() | |
{ | |
var h = new UniHash(UniHash.Alg.Hash32); | |
return bytes != null ? h.ComputeHash(bytes).ToInt() : 0; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
[SecuritySafeCritical] | |
public static unsafe bool Compare(byte[] a1, byte[] a2) | |
{ | |
if(a1 == null && a2 == null) | |
return true; | |
if(a1 == null || a2 == null || a1.Length != a2.Length) | |
return false; | |
fixed(byte* p1 = a1, p2 = a2) | |
{ | |
var Len = a1.Length; | |
byte* x1 = p1, x2 = p2; | |
while(Len > 7) | |
{ | |
if(*(long*) x2 != *(long*) x1) | |
return false; | |
x1 += 8; | |
x2 += 8; | |
Len -= 8; | |
} | |
switch(Len % 8) | |
{ | |
case 0: | |
break; | |
case 7: | |
if(*(int*) x2 != *(int*) x1) | |
return false; | |
x1 += 4; | |
x2 += 4; | |
if(*(short*) x2 != *(short*) x1) | |
return false; | |
x1 += 2; | |
x2 += 2; | |
if(*x2 != *x1) | |
return false; | |
break; | |
case 6: | |
if(*(int*) x2 != *(int*) x1) | |
return false; | |
x1 += 4; | |
x2 += 4; | |
if(*(short*) x2 != *(short*) x1) | |
return false; | |
break; | |
case 5: | |
if(*(int*) x2 != *(int*) x1) | |
return false; | |
x1 += 4; | |
x2 += 4; | |
if(*x2 != *x1) | |
return false; | |
break; | |
case 4: | |
if(*(int*) x2 != *(int*) x1) | |
return false; | |
break; | |
case 3: | |
if(*(short*) x2 != *(short*) x1) | |
return false; | |
x1 += 2; | |
x2 += 2; | |
if(*x2 != *x1) | |
return false; | |
break; | |
case 2: | |
if(*(short*) x2 != *(short*) x1) | |
return false; | |
break; | |
case 1: | |
if(*x2 != *x1) | |
return false; | |
break; | |
} | |
return true; | |
} | |
} | |
public byte[] ToByteArray() | |
{ | |
return bytes; | |
} | |
public BigInteger ToBigInteger() | |
{ | |
return bytes.ToBigInteger(); | |
} | |
public string ToBinaryString() | |
{ | |
var idx = bytes.Length - 1; | |
var base2 = new StringBuilder(bytes.Length * 8); | |
var binary = Convert.ToString(bytes[idx], 2); | |
base2.Append(binary); | |
for(idx--; idx >= 0; idx--) | |
base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0')); | |
return base2.ToString(); | |
} | |
public int GreatestCommonDivisor() | |
{ | |
var b = new List<byte>(bytes); | |
var g = new int[256]; | |
for(var i = 0; i < b.Count; ++i) | |
for(var j = i + 1; j < b.Count; ++j) | |
g[Gcd(b[i], b[j])]++; | |
var mv = 0; | |
var index = -1; | |
for(var i = 2; i < 256; ++i) | |
if(g[i] > mv) | |
{ | |
mv = g[i]; | |
index = i; | |
} | |
return index; | |
} | |
private static byte Gcd(byte a, byte b) | |
{ | |
while(b > 0) | |
{ | |
var r = (byte) (a % b); | |
a = b; | |
b = r; | |
} | |
return a; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment