Skip to content

Instantly share code, notes, and snippets.

@sandrock
Last active May 30, 2019 12:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sandrock/f38cf1b56a16e4d684398ac2117069ce to your computer and use it in GitHub Desktop.
Save sandrock/f38cf1b56a16e4d684398ac2117069ce to your computer and use it in GitHub Desktop.
C# convert a hexadecimal string to a byte array (tolerant to extra characters)
namespace Home
{
using System;
using System.Collections.Generic;
public static class ConvertEx
{
/// <summary>Reads a hex string into bytes</summary>
public static IEnumerable<byte> HexadecimalStringToBytes(string hex)
{
if (hex == null)
{
throw new ArgumentNullException(nameof(hex));
}
char c, c1 = default(char);
bool hasc1 = false;
unchecked
{
for (int i = 0; i < hex.Length; i++)
{
c = hex[i];
bool isValid = 'A' <= c && c <= 'f' || 'a' <= c && c <= 'f' || '0' <= c && c <= '9';
if (!hasc1)
{
if (isValid)
{
hasc1 = true;
}
}
else
{
hasc1 = false;
if (isValid)
{
yield return (byte)((GetHexVal(c1) << 4) + GetHexVal(c));
}
else
{
}
}
c1 = c;
}
}
}
/// <summary>Reads a hex string into a byte array</summary>
public static byte[] HexadecimalStringToByteArray(string hex)
{
if (hex == null)
{
throw new ArgumentNullException(nameof(hex));
}
var bytes = new List<byte>(hex.Length / 2);
foreach (var item in HexadecimalStringToBytes(hex))
{
bytes.Add(item);
}
return bytes.ToArray();
}
private static byte GetHexVal(char val)
{
return (byte)(val - (val < 0x3A ? 0x30 : val < 0x5B ? 0x37 : 0x57));
// ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^
// digits 0-9 upper char A-Z a-z
}
}
}
namespace Home
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Should;
using System;
using System.Collections.Generic;
using System.Linq;
[TestClass]
public class ConvertExTests
{
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void HexadecimalStringToBytes_Null()
{
var input = default(string);
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray();
}
[TestMethod]
public void HexadecimalStringToBytes_Empty()
{
var input = string.Empty;
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray();
result.ShouldNotBeNull();
result.Length.ShouldEqual(0);
}
[TestMethod]
public void HexadecimalStringToBytes_Simple()
{
var input = "00a0FF00";
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray();
result.ShouldNotBeNull();
result.Length.ShouldEqual(4);
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, });
}
[TestMethod]
public void HexadecimalStringToBytes_AllChars()
{
// generate 00-99 aa-ff AA-FF
var allStrings = new List<string>();
var allBytes = new List<byte>();
char c1, c2;
for (int i = 0; i < 16; i++)
{
c1 = i < 10 ? ((char)('0' + i)) : ((char)('a' + i - 10)).ToString()[0];
for (int j = 0; j < 16; j++)
{
c2 = j < 10 ? ((char)('0' + j)) : ((char)('a' + j - 10));
string value = c1.ToString() + c2;
allStrings.Add(value);
allStrings.Add(value.ToUpperInvariant());
allBytes.Add((byte)(i * 16 + j));
allBytes.Add((byte)(i * 16 + j));
}
}
var input = string.Concat(allStrings);
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray();
result.ShouldNotBeNull();
for (int i = 0; i < result.Length; i++)
{
result[i].ShouldEqual(allBytes[i], $"At {i}, val \"{allStrings[i]}\" should eq {allBytes[i]}, not {result[i]}");
}
result.Length.ShouldEqual(allBytes.Count);
}
[TestMethod]
public void HexadecimalStringToBytes_Skips()
{
var input = " 00 a0 FF 00\r\n00-a0-FF-00 ";
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray();
result.ShouldNotBeNull();
result.Length.ShouldEqual(8);
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, 0x00, 0xa0, 0xff, 0x00, });
}
[TestMethod]
public void HexadecimalStringToBytes_TooMuchTolerance()
{
var input = "Hello worlds.";
// would you expect an exception here? now there is none.
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray();
result.ShouldNotBeNull();
result.Length.ShouldEqual(1);
result.SequenceEqual(new byte[] { 0x1e, });
}
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void HexadecimalStringToByteArray_Null()
{
var input = default(string);
var result = ConvertEx.HexadecimalStringToByteArray(input);
}
[TestMethod]
public void HexadecimalStringToByteArray_Empty()
{
var input = string.Empty;
var result = ConvertEx.HexadecimalStringToByteArray(input);
result.ShouldNotBeNull();
result.Length.ShouldEqual(0);
}
[TestMethod]
public void HexadecimalStringToByteArray_Simple()
{
var input = "00a0FF00";
var result = ConvertEx.HexadecimalStringToByteArray(input);
result.ShouldNotBeNull();
result.Length.ShouldEqual(4);
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, });
}
[TestMethod]
public void HexadecimalStringToByteArray_Skips()
{
var input = "00 a0 FF 00\r\n00 a0 FF 00";
var result = ConvertEx.HexadecimalStringToByteArray(input);
result.ShouldNotBeNull();
result.Length.ShouldEqual(8);
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, 0x00, 0xa0, 0xff, 0x00, });
}
}
}
@sandrock
Copy link
Author

sandrock commented May 30, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment