2

I created the following function which will do as requested (convert HEX string to BitArray). I am not sure about the efficiency of the function, but my main problem now is that the Convert.ToInt64 function is endian specific. When this is ported over to alternate chipsets we will get different results (or exceptions). So can anyone think of an alternate way to do this conversion???

public BitArray convertHexToBitArray(string hexData)
    {
        string binary_values = "";
        BitArray binary_array;

            if (hexData.Length <= "FFFFFFFFFFFFFFFF".Length) // Max Int64
            {
                binary_values = Convert.ToString(Convert.ToInt64(hexData, 16), 2);
                binary_array = new BitArray(binary_values.Length);

                for (int i = 0; i < binary_array.Length; i++)
                {
                    if (binary_values[i] == '0')
                    {
                        binary_array[i] = false;
                    }
                    else
                    {
                        binary_array[i] = true;
                    }
                }
            }
   }

I removed most of the error / exception handling to keep this to size so plz forgive that.

Alex McKay
  • 103
  • 1
  • 2
  • 5
  • A 'chipset' is not BigEndian, a CPU core is. A hex string isn't BE either, the MSB is always on the left. If such a CPU core actually exists then it will run a .NET version that has a BE version of BitConverter. This question make little sense. – Hans Passant Nov 24 '10 at 18:59
  • Using C# mono this solution would eventually be ported onto Linux / Unix / Solaris / Non-stop and many other platforms. Our company has had problems in the past using the Convert class... Believe it or not, this is true. – Alex McKay Nov 24 '10 at 23:50

3 Answers3

9

here is a simple answer, should work with a string of any length:

public static BitArray ConvertHexToBitArray(string hexData)
{
    if (hexData == null)
        return null; // or do something else, throw, ...

    BitArray ba = new BitArray(4 * hexData.Length);
    for (int i = 0; i < hexData.Length; i++)
    {
        byte b = byte.Parse(hexData[i].ToString(), NumberStyles.HexNumber);
        for (int j = 0; j < 4; j++)
        {
            ba.Set(i * 4 + j, (b & (1 << (3 - j))) != 0);
        }
    }
    return ba;
}
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • I got some help from a co-worker and we came up with a similar solution. I am not very good with bit shifting but this looks good! – Alex McKay Nov 24 '10 at 19:45
6

Try this:

var int64 = Int64.Parse(hexData, NumberStyles.HexNumber);
var bytes = BitConverter.GetBytes(int64);
var bitArray = new BitArray(bytes);
alpha-mouse
  • 4,953
  • 24
  • 36
  • 1
    Very helpful, would require iteration to get past the 16 bytes mark, but you win the least amount of code award :) – Alex McKay Nov 24 '10 at 19:44
1

I haven't tested this (consider it pseduo code), but it would be fast:

    public static BitArray ConvertHexToBitArray(string hex)
    {
        Guard.AssertNotNullOrEmpty(hex, "hex");
        Guard.AssertHex(hex, "hex");

        var bits = new BitArray(hex.Length * 4);

        int pos = 0;

        foreach(char c in hex)
        {
            foreach(bool flag in LookupBits(c))
            {
                bits.Set(pos, flag);
                pos++;
            }
        }

        return bits;
    }

    private static readonly Dictionary<char, List<bool>> _hexVsBits = CreateHexLookupTable();

    private static Dictionary<char, List<bool>> CreateHexLookupTable()
    {
        var hexVsBits = new Dictionary<char, List<bool>>();

        hexVsBits.Add('0', CreateBitsArray(false, false, false, false));
        hexVsBits.Add('1', CreateBitsArray(false, false, false, true));
        hexVsBits.Add('2', CreateBitsArray(false, false, true, false));
        hexVsBits.Add('3', CreateBitsArray(false, false, true, true));
        hexVsBits.Add('4', CreateBitsArray(false, true, false, false));
        hexVsBits.Add('5', CreateBitsArray(false, true, false, true));
        hexVsBits.Add('6', CreateBitsArray(false, true, true, false));
        hexVsBits.Add('7', CreateBitsArray(false, true, true, true));

        // complete hex table

        return hexVsBits;
    }

    private static List<bool> CreateBitsArray(bool msb, bool msbMinusOne, bool lsbPlusOne, bool lsb)
    {
        var bits = new List<bool>(4);

        bits.Add(msb);
        bits.Add(msbMinusOne);
        bits.Add(lsbPlusOne);
        bits.Add(lsb);

        return bits;
    }

    private static IEnumerable<bool> LookupBits(char hexValue)
    {
        return _hexVsBits[hexValue];
    }
}

And the guards:

public static class Guard
{
    public static void AssertHex(string value, string parameterName)
    {
        foreach(char entry in value)
        {
            if (!Char.IsNumber(entry))
            {
                if (entry != 'a' && entry != 'A' && entry != 'b' && entry != 'B' 
                    && entry != 'c' && entry != 'C' && entry != 'd' && entry != 'D' && entry != 'e' && entry != 'E' && entry != 'f' && entry != 'F')
                {
                    throw new ArgumentException("Not a valid hexidecimal number", parameterName);
                }
            }
        }
    }

    public static void AssertNotNullOrEmpty(string value, string parameterName)
    {
        if (string.IsNullOrEmpty(value))
            throw new ArgumentNullException(parameterName);
    }
}
Marius
  • 9,208
  • 8
  • 50
  • 73