C# how to read first 4 and last 4 bits from byte ?
Use bitwise AND and shifts, like this:
byte b = 0xAB;
var low = b & 0x0F;
var high = b >> 4;
I would prefer simply using this -
byte a = 68;
byte high_bits = a>>4;
byte low_bits = a&15;
In a convenient struct:
Usage
var hb = new HalvedByte(5, 10);
hb.Low -= 3;
hb.High += 3;
Console.Write(string.Format("{0} / {1}", hb.Low, hb.High));
// 2, 13
Code
public struct HalvedByte
{
public byte Full { get; set; }
public byte Low
{
get { return (byte)(Full & 0x0F); }
set
{
if (value >= 16)
{
throw new ArithmeticException("Value must be between 0 and 16.");
}
Full = (byte)((High << 4) | (value & 0x0F));
}
}
public byte High
{
get { return (byte)(Full >> 4); }
set
{
if (value >= 16)
{
throw new ArithmeticException("Value must be between 0 and 16.");
}
Full = (byte)((value << 4) | Low);
}
}
public HalvedByte(byte full)
{
Full = full;
}
public HalvedByte(byte low, byte high)
{
if (low >= 16 || high >= 16)
{
throw new ArithmeticException("Values must be between 0 and 16.");
}
Full = (byte)((high << 4) | low);
}
}
Bonus: Array (Untested)
If you ever need to use an array of these half bytes, this will simplify accessing:
public class HalvedByteArray
{
public int Capacity { get; private set; }
public HalvedByte[] Array { get; private set; }
public byte this[int index]
{
get
{
if (index < 0 || index >= Capacity)
{
throw new IndexOutOfRangeException();
}
var hb = Array[index / 2];
return (index % 2 == 0) ? hb.Low : hb.High;
}
set
{
if (index < 0 || index >= Capacity)
{
throw new IndexOutOfRangeException();
}
var hb = Array[index / 2];
if (index % 2 == 0)
{
hb.Low = value;
}
else
{
hb.High = value;
}
}
}
public HalvedByteArray(int capacity)
{
if (capacity < 0)
{
throw new ArgumentException("Capacity must be positive.", "capacity");
}
Capacity = capacity;
Array = new HalvedByte[capacity / 2];
}
}
Simple method to do it.
Example use :
A: 10101110
B: 00001110
Get last 4 bits from A, so that output is like B
getBitRange(10101110, 0, 4);
//gets a bits from a byte, and return a byte of the new bits
byte getBitRange(byte data, int start, int _end){
//shift binary to starting point of range
byte shifted = (data >> start);
//calculate range length (+1 for 0 index)
int rangeLength = (_end-start)+1;
//get binary mask based on range length
byte maskBinary;
switch (rangeLength){
case 1: maskBinary = 0b00000001; break;
case 2: maskBinary = 0b00000011; break;
case 3: maskBinary = 0b00000111; break;
case 4: maskBinary = 0b00001111; break;
case 5: maskBinary = 0b00011111; break;
case 6: maskBinary = 0b00111111; break;
case 7: maskBinary = 0b01111111; break;
case 8: maskBinary = 0b11111111; break;
default:
// default statements
Serial.println("Error: Range length too long!!");
}
//cancel out
byte finalByte = (shifted & maskBinary);
return finalByte;
}
Related
I'm looking for a way to convert a long string of binary to a hex string.
the binary string looks something like this "0110011010010111001001110101011100110100001101101000011001010110001101101011"
I've tried using
hex = String.Format("{0:X2}", Convert.ToUInt64(hex, 2));
but that only works if the binary string fits into a Uint64 which if the string is long enough it won't.
is there another way to convert a string of binary into hex?
Thanks
I just knocked this up. Maybe you can use as a starting point...
public static string BinaryStringToHexString(string binary)
{
if (string.IsNullOrEmpty(binary))
return binary;
StringBuilder result = new StringBuilder(binary.Length / 8 + 1);
// TODO: check all 1's or 0's... throw otherwise
int mod4Len = binary.Length % 8;
if (mod4Len != 0)
{
// pad to length multiple of 8
binary = binary.PadLeft(((binary.Length / 8) + 1) * 8, '0');
}
for (int i = 0; i < binary.Length; i += 8)
{
string eightBits = binary.Substring(i, 8);
result.AppendFormat("{0:X2}", Convert.ToByte(eightBits, 2));
}
return result.ToString();
}
This might help you:
string HexConverted(string strBinary)
{
string strHex = Convert.ToInt32(strBinary,2).ToString("X");
return strHex;
}
Convert.ToInt32("1011", 2).ToString("X");
For string longer than this, you can simply break it into multiple bytes:
var binary = "0110011010010111001001110101011100110100001101101000011001010110001101101011";
var hex = string.Join(" ",
Enumerable.Range(0, binary.Length / 8)
.Select(i => Convert.ToByte(binary.Substring(i * 8, 8), 2).ToString("X2")));
I came up with this method. I am new to programming and C# but I hope you will appreciate it:
static string BinToHex(string bin)
{
StringBuilder binary = new StringBuilder(bin);
bool isNegative = false;
if (binary[0] == '-')
{
isNegative = true;
binary.Remove(0, 1);
}
for (int i = 0, length = binary.Length; i < (4 - length % 4) % 4; i++) //padding leading zeros
{
binary.Insert(0, '0');
}
StringBuilder hexadecimal = new StringBuilder();
StringBuilder word = new StringBuilder("0000");
for (int i = 0; i < binary.Length; i += 4)
{
for (int j = i; j < i + 4; j++)
{
word[j % 4] = binary[j];
}
switch (word.ToString())
{
case "0000": hexadecimal.Append('0'); break;
case "0001": hexadecimal.Append('1'); break;
case "0010": hexadecimal.Append('2'); break;
case "0011": hexadecimal.Append('3'); break;
case "0100": hexadecimal.Append('4'); break;
case "0101": hexadecimal.Append('5'); break;
case "0110": hexadecimal.Append('6'); break;
case "0111": hexadecimal.Append('7'); break;
case "1000": hexadecimal.Append('8'); break;
case "1001": hexadecimal.Append('9'); break;
case "1010": hexadecimal.Append('A'); break;
case "1011": hexadecimal.Append('B'); break;
case "1100": hexadecimal.Append('C'); break;
case "1101": hexadecimal.Append('D'); break;
case "1110": hexadecimal.Append('E'); break;
case "1111": hexadecimal.Append('F'); break;
default:
return "Invalid number";
}
}
if (isNegative)
{
hexadecimal.Insert(0, '-');
}
return hexadecimal.ToString();
}
Considering four bits can be expressed by one hex value, you can simply go by groups of four and convert them seperately, the value won't change that way.
string bin = "11110110";
int rest = bin.Length % 4;
if(rest != 0)
bin = new string('0', 4-rest) + bin; //pad the length out to by divideable by 4
string output = "";
for(int i = 0; i <= bin.Length - 4; i +=4)
{
output += string.Format("{0:X}", Convert.ToByte(bin.Substring(i, 4), 2));
}
If you want to iterate over the hexadecimal representation of each byte in the string, you could use the following extension. I've combined Mitch's answer with this.
static class StringExtensions
{
public static IEnumerable<string> ToHex(this String s) {
if (s == null)
throw new ArgumentNullException("s");
int mod4Len = s.Length % 8;
if (mod4Len != 0)
{
// pad to length multiple of 8
s = s.PadLeft(((s.Length / 8) + 1) * 8, '0');
}
int numBitsInByte = 8;
for (var i = 0; i < s.Length; i += numBitsInByte)
{
string eightBits = s.Substring(i, numBitsInByte);
yield return string.Format("{0:X2}", Convert.ToByte(eightBits, 2));
}
}
}
Example:
string test = "0110011010010111001001110101011100110100001101101000011001010110001101101011";
foreach (var hexVal in test.ToHex())
{
Console.WriteLine(hexVal);
}
Prints
06
69
72
75
73
43
68
65
63
6B
If you're using .NET 4.0 or later and if you're willing to use System.Numerics.dll (for BigInteger class), the following solution works fine:
public static string ConvertBigBinaryToHex(string bigBinary)
{
BigInteger bigInt = BigInteger.Zero;
int exponent = 0;
for (int i = bigBinary.Length - 1; i >= 0; i--, exponent++)
{
if (bigBinary[i] == '1')
bigInt += BigInteger.Pow(2, exponent);
}
return bigInt.ToString("X");
}
Considering four bits can be expressed by one hex value, you can simply go by groups of four and convert them seperately, the value won't change that way.
string bin = "11110110";
int rest = bin.Length % 4;
bin = bin.PadLeft(rest, '0'); //pad the length out to by divideable by 4
string output = "";
for(int i = 0; i <= bin.Length - 4; i +=4)
{
output += string.Format("{0:X}", Convert.ToByte(bin.Substring(i, 4), 2));
}
static string BinToHex(string bin)
{
if (bin == null)
throw new ArgumentNullException("bin");
if (bin.Length % 8 != 0)
throw new ArgumentException("The length must be a multiple of 8", "bin");
var hex = Enumerable.Range(0, bin.Length / 8)
.Select(i => bin.Substring(8 * i, 8))
.Select(s => Convert.ToByte(s, 2))
.Select(b => b.ToString("x2"));
return String.Join(null, hex);
}
Using LINQ
string BinaryToHex(string binaryString)
{
var offset = 0;
StringBuilder sb = new();
while (offset < binaryString.Length)
{
var nibble = binaryString
.Skip(offset)
.Take(4);
sb.Append($"{Convert.ToUInt32(nibble.toString()), 2):X}");
offset += 4;
}
return sb.ToString();
}
You can take the input number four digit at a time. Convert this digit to ex ( as you did is ok ) then concat the string all together. So you obtain a string representing the number in hex, independetly from the size. Depending on where start MSB on your input string, may be the output string you obtain the way i described must be reversed.
What is the correct way to send DateTime in UTC to a SNMPV2 event using SNMPSHARPNET ?
http://www.snmpsharpnet.com/
We have been using TimeTicks AsnType but have run into issues of data over 29 and half days.
This is the code for reference :
AsnType newMIBValue = null;
if (!string.IsNullOrEmpty(MIBValueString))
{
switch (DataType)
{
case MIBDataType.DateAndTime:
//newMIBValue = new TimeTicks(MIBValueString);
newMIBValue = ConvertDateTimeToOctetString(MIBValueString);
break;
case MIBDataType.SnmpAdminString:
newMIBValue = new OctetString(MIBValueString);
break;
case MIBDataType.TimeTicks:
newMIBValue = new TimeTicks(MIBValueString);
break;
case MIBDataType.IPAddress:
newMIBValue = new IpAddress(MIBValueString);
break;
case MIBDataType.Integer:
newMIBValue = new Integer32(MIBValueString);
break;
default:
break;
}
}
Use OCTET STRING for datetime stuff. TimeTicks is a non-negative integer which specifies the elapsed time between two events, in units of hundredth of a second.
A colleague of mine helped me put this code. Apparently we have send a byte array of hex values per SNMP specification.
private OctetString ConvertStringToOctetString(DateTime dateTimeValueInUTCDateAndTime)
{
var yearInString = dateTimeValueInUTCDateAndTime.Year.ToString("X");
byte[] bytesArray = ConvertToByteArray(string.Format("{0}{1}{2}{3}{4}{5}{6}",
yearInString,
dateTimeValueInUTCDateAndTime.Month.ToString("X").PadLeft(2, '0'),
dateTimeValueInUTCDateAndTime.Day.ToString("X").PadLeft(2, '0'),
dateTimeValueInUTCDateAndTime.Hour.ToString("X").PadLeft(2, '0'),
dateTimeValueInUTCDateAndTime.Minute.ToString("X").PadLeft(2, '0'),
dateTimeValueInUTCDateAndTime.Second.ToString("X").PadLeft(2, '0'),
"00"
));
return new OctetString(bytesArray);
}
public byte[] ConvertToByteArray(string value)
{
byte[] bytes = null;
if (String.IsNullOrEmpty(value))
bytes = null;
else
{
int string_length = value.Length;
int character_index = (value.StartsWith("0x", StringComparison.Ordinal)) ? 2 : 0; // Does the string define leading HEX indicator '0x'. Adjust starting index accordingly.
int number_of_characters = string_length - character_index;
bool add_leading_zero = false;
if (0 != (number_of_characters % 2))
{
add_leading_zero = true;
number_of_characters += 1; // Leading '0' has been striped from the string presentation.
}
bytes = new byte[number_of_characters / 2]; // Initialize our byte array to hold the converted string.
int write_index = 0;
if (add_leading_zero)
{
bytes[write_index++] = FromCharacterToByte(value[character_index], character_index);
character_index += 1;
}
for (int read_index = character_index; read_index < value.Length; read_index += 2)
{
byte upper = FromCharacterToByte(value[read_index], read_index, 4);
byte lower = FromCharacterToByte(value[read_index + 1], read_index + 1);
bytes[write_index++] = (byte)(upper | lower);
}
}
return bytes;
}
private byte FromCharacterToByte(char character, int index, int shift = 0)
{
byte value = (byte)character;
if (((0x40 < value) && (0x47 > value)) || ((0x60 < value) && (0x67 > value)))
{
if (0x40 == (0x40 & value))
{
if (0x20 == (0x20 & value))
value = (byte)(((value + 0xA) - 0x61) << shift);
else
value = (byte)(((value + 0xA) - 0x41) << shift);
}
}
else if ((0x29 < value) && (0x40 > value))
value = (byte)((value - 0x30) << shift);
else
throw new InvalidOperationException(String.Format("Character '{0}' at index '{1}' is not valid alphanumeric character.", character, index));
return value;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do you convert Byte Array to Hexadecimal String, and vice versa?
I need an efficient and fast way to do this conversion. I have tried two different ways, but they are not efficient enough for me. Is there any other quick method to accomplish this in a real-time fashion for an application with huge data?
public byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length / 2).Select(x => Byte.Parse(hex.Substring(2 * x, 2), NumberStyles.HexNumber)).ToArray();
}
The above one felt more efficient to me.
public static byte[] stringTobyte(string hexString)
{
try
{
int bytesCount = (hexString.Length) / 2;
byte[] bytes = new byte[bytesCount];
for (int x = 0; x < bytesCount; ++x)
{
bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
}
return bytes;
}
catch
{
throw;
}
If you really need efficiency then:
Don't create substrings
Don't create an iterator
Or, and get rid of try blocks which only have a catch block which rethrows... for simplicity rather than efficiency though.
This would be a pretty efficient version:
public static byte[] ParseHex(string hexString)
{
if ((hexString.Length & 1) != 0)
{
throw new ArgumentException("Input must have even number of characters");
}
int length = hexString.Length / 2;
byte[] ret = new byte[length];
for (int i = 0, j = 0; i < length; i++)
{
int high = ParseNybble(hexString[j++]);
int low = ParseNybble(hexString[j++]);
ret[i] = (byte) ((high << 4) | low);
}
return ret;
}
private static int ParseNybble(char c)
{
// TODO: Benchmark using if statements instead
switch (c)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return c - '0';
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
return c - ('a' - 10);
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
return c - ('A' - 10);
default:
throw new ArgumentException("Invalid nybble: " + c);
}
return c;
}
The TODO refers to an alternative like this. I haven't measured which is faster.
private static int ParseNybble(char c)
{
if (c >= '0' && c <= '9')
{
return c - '0';
}
c = (char) (c & ~0x20);
if (c >= 'A' && c <= 'F')
{
return c - ('A' - 10);
}
throw new ArgumentException("Invalid nybble: " + c);
}
I took the benchmarking code from the other question, and reworked it to test the hex to bytes methods given here:
HexToBytesJon: 36979.7 average ticks (over 150 runs)
HexToBytesJon2: 35886.4 average ticks (over 150 runs)
HexToBytesJonCiC: 31230.2 average ticks (over 150 runs)
HexToBytesJase: 15359.1 average ticks (over 150 runs)
HexToBytesJon is Jon's first version, and HexToBytesJon2 is the second variant.
HexToBytesJonCiC is Jon's version with CodesInChaos's suggested code.
HexToBytesJase is my attempt, based on both the above but with alternative nybble conversion which eschews error checking, and branching:
public static byte[] HexToBytesJase(string hexString)
{
if ((hexString.Length & 1) != 0)
{
throw new ArgumentException("Input must have even number of characters");
}
byte[] ret = new byte[hexString.Length/2];
for (int i = 0; i < ret.Length; i++)
{
int high = hexString[i*2];
int low = hexString[i*2+1];
high = (high & 0xf) + ((high & 0x40) >> 6) * 9;
low = (low & 0xf) + ((low & 0x40) >> 6) * 9;
ret[i] = (byte)((high << 4) | low);
}
return ret;
}
As a variant of Jon's if based ParseNybble:
public static byte[] ParseHex(string hexString)
{
if ((hexString.Length & 1) != 0)
{
throw new ArgumentException("Input must have even number of characters");
}
byte[] ret = new byte[hexString.Length / 2];
for (int i = 0; i < ret.Length; i++)
{
int high = ParseNybble(hexString[i*2]);
int low = ParseNybble(hexString[i*2+1]);
ret[i] = (byte) ((high << 4) | low);
}
return ret;
}
private static int ParseNybble(char c)
{
unchecked
{
uint i = (uint)(c - '0');
if(i < 10)
return (int)i;
i = ((uint)c & ~0x20u) - 'A';
if(i < 6)
return (int)i+10;
throw new ArgumentException("Invalid nybble: " + c);
}
}
In C#, is there a way to right/left shift an entire byte array (and subsequently adding a byte to a particular side for the last bit isn't lost)?
I know this sounds like a weird request, but I'd still like to know if its possible and/or how to begin doing it.
Just for grins. shifting and rotating bytes in a byte array. (not bitshifting)
shift left, zero fill:
mybytes.Skip(1).Concat(new byte[] { 0 }).ToArray();
shift right, zero fill:
(new byte[] {0}).Concat(mybytes.Take(mybytes.Length - 1)).ToArray();
rotate left:
mybytes.Skip(1).Concat(mybytes.Take(1)).ToArray();
rotate right:
mybytes.Skip(mbytes.Length - 1).Concat(mbytes.Take(mbytes.Length - 1)).ToArray();
Yes, you can. See the following methods I wrote:
/// <summary>
/// Rotates the bits in an array of bytes to the left.
/// </summary>
/// <param name="bytes">The byte array to rotate.</param>
public static void RotateLeft(byte[] bytes)
{
bool carryFlag = ShiftLeft(bytes);
if (carryFlag == true)
{
bytes[bytes.Length - 1] = (byte)(bytes[bytes.Length - 1] | 0x01);
}
}
/// <summary>
/// Rotates the bits in an array of bytes to the right.
/// </summary>
/// <param name="bytes">The byte array to rotate.</param>
public static void RotateRight(byte[] bytes)
{
bool carryFlag = ShiftRight(bytes);
if (carryFlag == true)
{
bytes[0] = (byte)(bytes[0] | 0x80);
}
}
/// <summary>
/// Shifts the bits in an array of bytes to the left.
/// </summary>
/// <param name="bytes">The byte array to shift.</param>
public static bool ShiftLeft(byte[] bytes)
{
bool leftMostCarryFlag = false;
// Iterate through the elements of the array from left to right.
for (int index = 0; index < bytes.Length; index++)
{
// If the leftmost bit of the current byte is 1 then we have a carry.
bool carryFlag = (bytes[index] & 0x80) > 0;
if (index > 0)
{
if (carryFlag == true)
{
// Apply the carry to the rightmost bit of the current bytes neighbor to the left.
bytes[index - 1] = (byte)(bytes[index - 1] | 0x01);
}
}
else
{
leftMostCarryFlag = carryFlag;
}
bytes[index] = (byte)(bytes[index] << 1);
}
return leftMostCarryFlag;
}
/// <summary>
/// Shifts the bits in an array of bytes to the right.
/// </summary>
/// <param name="bytes">The byte array to shift.</param>
public static bool ShiftRight(byte[] bytes)
{
bool rightMostCarryFlag = false;
int rightEnd = bytes.Length - 1;
// Iterate through the elements of the array right to left.
for (int index = rightEnd; index >= 0; index--)
{
// If the rightmost bit of the current byte is 1 then we have a carry.
bool carryFlag = (bytes[index] & 0x01) > 0;
if (index < rightEnd)
{
if (carryFlag == true)
{
// Apply the carry to the leftmost bit of the current bytes neighbor to the right.
bytes[index + 1] = (byte)(bytes[index + 1] | 0x80);
}
}
else
{
rightMostCarryFlag = carryFlag;
}
bytes[index] = (byte)(bytes[index] >> 1);
}
return rightMostCarryFlag;
}
It seems you are performing bit operations on large amount of bits storing them in a byte array. Consider using BitArray class and BitVector32 Structure. Depending on what you are doing with bits you can create a class like this. Note that shifting works in O(1) instead of O(n).
public class BitRing : IEnumerable<bool>
{
private readonly BitArray m_InnerBitArray;
private int m_StarIndex;
public BitRing(byte[] bytes)
{
m_InnerBitArray = new BitArray(bytes);
m_StarIndex = 0;
}
public void ShiftLeft()
{
m_StarIndex++;
}
public void ShiftRight()
{
m_StarIndex--;
}
public bool this[int i]
{
get
{
int index = GetIndex(i);
return m_InnerBitArray[index];
}
set
{
int index = GetIndex(i);
m_InnerBitArray[index] = value;
}
}
private int GetIndex(int i)
{
return i - m_StarIndex%m_InnerBitArray.Count;
}
public IEnumerator<bool> GetEnumerator()
{
for (int i = m_StarIndex; i < m_InnerBitArray.Count; i++)
{
yield return m_InnerBitArray[i];
}
for (int i = 0; i < m_StarIndex; i++)
{
yield return m_InnerBitArray[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I've given it some more thought and realized that this probably fits the question better:
public static void Main()
{
byte[] bytes = new byte[] { 0xFF, 0x01, 0x80, 0x81 };
Stack<bool> bitStack = CreateBitStack(bytes);
ShiftLeftExpand(bitStack, 1);
byte[] newBytes = CreateByteArray(bitStack);
}
public static void ShiftLeftExpand(Stack<bool> bitStack, int count)
{
while (count-- > 0)
{
bitStack.Push(false);
}
}
public static Stack<bool> CreateBitStack(byte[] bytes)
{
Stack<bool> bitStack = new Stack<bool>(bytes.Length * 8);
for (int bytePosition = 0; bytePosition < bytes.Length; bytePosition++)
{
for (int bitPosition = 7; bitPosition >= 0; bitPosition--)
{
int bitMask = 0x01 << bitPosition;
bitStack.Push((bytes[bytePosition] & bitMask) > 0);
}
}
return bitStack;
}
public static byte[] CreateByteArray(Stack<bool> bitStack)
{
int newArrayLength = (int)Math.Ceiling(bitStack.Count / 8.0);
byte[] bytes = new byte[newArrayLength];
int bitCounter = 0;
while (bitStack.Count > 0)
{
bool? bitValue = bitStack.Pop();
int bitPosition = bitCounter % 8;
int bytePosition = newArrayLength - 1 - bitCounter / 8;
if (bitValue == true)
{
bytes[bytePosition] = (byte)(bytes[bytePosition] | (0x01 << bitPosition));
}
bitCounter++;
}
return bytes;
}
A similar technique can be applied to perform the right shift.
Linq way:
static class Shifter
{
public static byte[] ShiftLeft(this byte[] array, int n)
{
var a = array.Select(x => (byte)(x >> 8 - n % 8)).Concat(new byte[(7 + n) / 8]).Select((x, i) => new Tuple<int, byte>(i - (n % 8 == 0 ? 0 : 1), x));
var b = array.Select(x => (byte)(x << n % 8)).Concat(new byte[n / 8]).Select((x, i) => new Tuple<int, byte>(i, x));
return (from x in a
join y in b on x.Item1 equals y.Item1 into yy
from y in yy.DefaultIfEmpty()
select (byte)(x.Item2 | (y == null ? 0 : y.Item2))).ToArray();
}
public static byte[] ShiftRight(this byte[] array, int n)
{
return (new byte[n/8]).Concat(ShiftLeft(array, (8 - (n%8))%8)).ToArray();
}
}
I don't think there's a built-in way. I implemented the shift-left operation you described below (assuming little endian). It's not quite as elegant as you can do with x86 assembly (shift with carry instructions), but pretty close to what you could do with C.
Alternately, you can almost use the BigInteger struct (.NET 4 and above) which has a constructor that takes a byte array and a ToByteArray method. But its shift left operation sign-extends the high byte and its shift right operation truncates. So you'd need to compensate for both to get the exact behavior you described.
// Left-shifts a byte array in place. Assumes little-endian. Throws on overflow.
static public void ShiftByteArrayLeft(byte[] array)
{
if (array == null)
throw new ArgumentNullException("array");
if (array[array.Length - 1] >= 0x80)
throw new OverflowException();
// move left-to-right, left-shifting each byte
for (int i = array.Length - 1; i >= 1; --i)
{
// left-shift current byte
array[i] <<= 1;
// carry the bit from the next/right byte if needed
if (array[i - 1] >= 0x80)
++array[i];
}
// finally shift the left-shift the right-most byte
array[0] <<= 1;
}
// Left-shifts a byte array in place. Assumes little-endian. Grows array as needed.
static public void ShiftByteArrayLeftAutoGrow(ref byte[] array)
{
if (array == null)
throw new ArgumentNullException("array");
if (array[array.Length - 1] >= 0x80)
{
// allocate a bigger array and do the left-shift on it
byte[] oldArray = array;
array = new byte[oldArray.Length + 1];
Array.Copy(oldArray, 0, array, 0, oldArray.Length);
}
ShiftByteArrayLeft(array);
}
Shift left:
for (int i = byteArray.Length - 1; i >= 0; i--) byteArray[i] = (byte)((byteArray[i] << 1) | ((i == 0) ? 0 : byteArray[i - 1] >> 7));
Shift right:
for (int i = 0; i <= byteArray.Length - 1; i++) byteArray[i] = (byte)((byteArray[i] >> 1) | ((i == byteArray.Length - 1) ? 0 : byteArray[i + 1] << 7));
These two functions will shift the bits in an array of bytes the specified amount, shifting them into neighboring bytes as needed. Optionally, they can wrap the bits from one end of the array to the other. Note that they create a new array, but the code can be easily changed to modify the passed 'array' instead...
public static byte[] ShiftRight(byte[] array, int shift, bool wrap = false) {
if(shift < 0) {
throw new ArgumentOutOfRangeException("shift");
} else if(shift == 0) {
return (byte[])array.Clone();
} else {
if(wrap) shift %= (array.Length * 8);
if(shift >= (array.Length * 8)) return new byte[array.Length];
var offset = (shift / 8);
shift %= 8;
var ʀ = new byte[array.Length];
for(var ɪ = 0; ɪ < ʀ.Length; ɪ++) {
var indexL_ɪ = (ɪ + offset);
var indexH_ɪ = (ɪ + offset + 1);
if(wrap) {
if(indexL_ɪ >= array.Length) indexL_ɪ -= array.Length;
if(indexH_ɪ >= array.Length) indexH_ɪ -= array.Length;
}
if(indexL_ɪ < array.Length) ʀ[ɪ] = (byte)(array[indexL_ɪ] >> shift);
if(indexH_ɪ < array.Length) ʀ[ɪ] |= (byte)(array[indexH_ɪ] << (8 - shift));
}
return ʀ;
}
}
public static byte[] ShiftLeft(byte[] array, int shift, bool wrap = false) {
if(shift < 0) {
throw new ArgumentOutOfRangeException("shift");
} else if(shift == 0) {
return (byte[])array.Clone();
} else {
if(wrap) shift %= (array.Length * 8);
if(shift >= (array.Length * 8)) return new byte[array.Length];
var offset = (shift / 8);
shift %= 8;
for(var ɪ = 0; ɪ < ʀ.Length; ɪ++) {
var indexL_ɪ = (ɪ - offset - 1);
var indexH_ɪ = (ɪ - offset);
if(wrap) {
if(indexL_ɪ < 0) indexL_ɪ += array.Length;
if(indexH_ɪ < 0) indexH_ɪ += array.Length;
}
if(indexL_ɪ >= 0) ʀ[ɪ] = (byte)(array[indexL_ɪ] >> (8 - shift));
if(indexH_ɪ >= 0) ʀ[ɪ] |= (byte)(array[indexH_ɪ] << shift);
}
return ʀ;
}
}
I copied and pasted this binary data out of sql server, which I am unable to query at this time.
0xBAC893CAB8B7FE03C927417A2A3F6A60BD30FF35E250011CB25507EBFCD5223B
How do I convert it back to a byte array in c#?
Something like this:
using System;
public static class Parser
{
static void Main()
{
string hex = "0xBAC893CAB8B7FE03C927417A2A3F6A6"
+ "0BD30FF35E250011CB25507EBFCD5223B";
byte[] parsed = ParseHex(hex);
// Just for confirmation...
Console.WriteLine(BitConverter.ToString(parsed));
}
public static byte[] ParseHex(string hex)
{
int offset = hex.StartsWith("0x") ? 2 : 0;
if ((hex.Length % 2) != 0)
{
throw new ArgumentException("Invalid length: " + hex.Length);
}
byte[] ret = new byte[(hex.Length-offset)/2];
for (int i=0; i < ret.Length; i++)
{
ret[i] = (byte) ((ParseNybble(hex[offset]) << 4)
| ParseNybble(hex[offset+1]));
offset += 2;
}
return ret;
}
static int ParseNybble(char c)
{
if (c >= '0' && c <= '9')
{
return c-'0';
}
if (c >= 'A' && c <= 'F')
{
return c-'A'+10;
}
if (c >= 'a' && c <= 'f')
{
return c-'a'+10;
}
throw new ArgumentException("Invalid hex digit: " + c);
}
}
(EDIT: Now slightly more efficient - no substrings required...)
It's possible that ParseNybble could be more efficient. For example, a switch/case may be more efficient:
static int ParseNybble(char c)
{
switch (c)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
return c-'0';
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
return c-'A'+10;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
return c-'a'+10;
}
throw new ArgumentException("Invalid hex digit: " + c);
}
or possibly a lookup array:
// Omitted for brevity... I'm sure you get the gist
private static readonly int[] NybbleLookup = BuildLookup();
private int ParseNybble(char c)
{
if (c > 'f')
{
throw new ArgumentException("Invalid hex digit: " + c);
}
int ret = NybbleLookup[c];
if (ret == -1)
{
throw new ArgumentException("Invalid hex digit: " + c);
}
return ret;
}
I haven't benchmarked any of these, and I've no idea which would be the fastest. The current solution is probably the simplest though.
Consider leveraging a Framework class that already exposes the ability to perform hex conversion, XmlReader for example:
public static byte[] HexToBytes(this string hexEncodedBytes, int start, int end)
{
int length = end - start;
const string tagName = "hex";
string fakeXmlDocument = String.Format("<{1}>{0}</{1}>",
hexEncodedBytes.Substring(start, length),
tagName);
var stream = new MemoryStream(Encoding.ASCII.GetBytes(fakeXmlDocument));
XmlReader reader = XmlReader.Create(stream, new XmlReaderSettings());
int hexLength = length / 2;
byte[] result = new byte[hexLength];
reader.ReadStartElement(tagName);
reader.ReadContentAsBinHex(result, 0, hexLength);
return result;
}
usage:
string input = "0xBAC893CAB8B7FE03C927417A2A3F6A60BD30FF35E250011CB255";
byte[] bytes = input.HexToBytes(2, input.Length);
Simple:
string hexnum = "0000000F"; // Represents 15
int value = int.Parse(hexnum, System.Globalization.NumberStyles.HexNumber);
All you have to remember to do is for an int to divide the hex number up into groups of 8 hex digits (hex are 4 bits each, and CLR int type is 32 bits, hence 8 digits per int). There's also a byte.Parse() that works the same, but pass in two hex digits at a time.
Something like this:
public byte[] ParseHexString(string text)
{
if ((text.Length % 2) != 0)
{
throw new ArgumentException("Invalid length: " + text.Length);
}
if (text.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase))
{
text = text.Substring(2);
}
int arrayLength = text.Length / 2;
byte[] byteArray = new byte[arrayLength];
for (int i = 0; i < arrayLength; i++)
{
byteArray[i] = byte.Parse(text.Substring(i*2, 2), NumberStyles.HexNumber);
}
return byteArray;
}
You will need to modify this a little bit (for example, skip over the first two characters), but it does handle spaces in the string:
/// <summary>
/// Decodes a hex string, ignoring all non-hex characters, and stores
/// the decodes series of bytes into the shared buffer. This returns
/// the number of bytes that were decoded.
/// <para>Hex characters are [0-9, a-f, A-F].</para>
/// </summary>
/// <param name="hexString">String to parse into bytes.</param>
/// <param name="buffer">Buffer into which to store the decoded binary data.</param>
/// <returns>The number of bytes decoded.</returns>
private static int DecodeHexIntoBuffer(string hexString, byte[] buffer)
{
int count = 0;
bool haveFirst = false;
bool haveSecond = false;
char first = '0';
char second = '0';
for (int i = 0; i < hexString.Length; i++)
{
if (!haveFirst)
{
first = hexString[i];
haveFirst = char.IsLetterOrDigit(first);
// we have to continue to the next iteration
// or we will miss characters
continue;
}
if (!haveSecond)
{
second = hexString[i];
haveSecond = char.IsLetterOrDigit(second);
}
if (haveFirst && haveSecond)
{
string hex = "" + first + second;
byte nextByte;
if (byte.TryParse(hex, NumberStyles.HexNumber, null, out nextByte))
{
// store the decoded byte into the next slot of the buffer
buffer[count++] = nextByte;
}
// reset the flags
haveFirst = haveSecond = false;
}
}
return count;
}
Actually, there's an easier way to convert two characters at a time to a byte:
/// <summary>
/// This will convert a hex-encoded string to byte data
/// </summary>
/// <param name="hexData">The hex-encoded string to convert</param>
/// <returns>The bytes that make up the hex string</returns>
public static byte[] FromHex(string hexData)
{
List<byte> data = new List<byte>();
string byteSet = string.Empty;
int stringLen = hexData.Length;
int length = 0;
for (int i = 0; i < stringLen; i = i + 2)
{
length = (stringLen - i) > 1 ? 2 : 1;
byteSet = hexData.Substring(i, length);
// try and parse the data
data.Add(Convert.ToByte(byteSet, 16 /*base*/));
} // next set
return data.ToArray();
}
Slow yet fun way :D
public static byte[] StringToByteArray(string hex)
{
hex = hex.Replace(" ", "");
hex = hex.Replace(":", "");
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
-jD
I use this for C#, from similar code in Java.
private static char[] hexdigit = "0123456789abcdef".ToCharArray();
public static string hexlify(string argbuf) {
int arglen = argbuf.Length;
char[] argca = argbuf.ToCharArray ();
StringBuilder retbuf = new StringBuilder(arglen * 2);
for (int i = 0; i < arglen; i++) {
char ch = argca[i];
retbuf.Append(hexdigit[(ch >> 4) & 0xF]);
retbuf.Append(hexdigit[ch & 0xF]);
}
return retbuf.ToString();
}
public static string unhexlify(string argbuf) {
int arglen = argbuf.Length;
if (arglen % 2 != 0) {
throw new ArgumentOutOfRangeException ("Odd-length string");
}
char[] argca = argbuf.ToCharArray ();
StringBuilder retbuf = new StringBuilder(arglen / 2);
for (int i = 0; i < arglen; i += 2) {
int top = Convert.ToInt32 (argca[i].ToString (), 16);
int bot = Convert.ToInt32 (argca[i + 1].ToString (), 16);
if (top == -1 || bot == -1) {
throw new ArgumentOutOfRangeException ("Non-hexadecimal digit found");
}
retbuf.Append((char) ((top << 4) + bot));
}
return retbuf.ToString();
}
maybe this one is cute!
string source = "Hello World!";
using (SHA256 sha256Hash = SHA256.Create())
{
//From String to byte array
byte[] sourceBytes = Encoding.UTF8.GetBytes(source);
byte[] hashBytes = sha256Hash.ComputeHash(sourceBytes);
string hash = BitConverter.ToString(hashBytes).Replace("-", String.Empty);
Console.WriteLine("The SHA256 hash of " + source + " is: " + hash);
}