Kane
Kane

Reputation: 377

How to check bits of a byte[]

I am getting a string that has been Base64 encoded from a byte[] data, and I have to check the bits inside it.

When I get "AAAB", I decode it to a byte[], and as A = {000000} and B = {000001}, I get [ {00000000} {00000000} {00000001} ].

The thing is that i want to count which bite is 1. In the case above, the bit that is 1 is the number 24, so i want to get 24.

So that is what I wanted to do:

EDITED WITH THE SOLUTION PROPOSED BY SCOTT:

using using System.Linq;

string stringData = "AAAB"; // {000000} {000000} {000000} {000001}
byte[] byteData = Convert.FromBase64String(stringData); // {00000000}{00000000}{00000001}
BitArray bitData = new BitArray(byteData.Reverse().ToArray()); // {100000000000000000000000}

 var i = bitData .Length;
 foreach (bool bit in bitData )
                        {
   if (bit)
   {
     //display i, the bit 1
   }
   j--;
 }

Thanks a lot, Scott!

Upvotes: 1

Views: 2492

Answers (3)

Scott Chamberlain
Scott Chamberlain

Reputation: 127543

The easiest way to handle this is convert the byte[] in to a BitArray

string stringData = "AAAB"; // {000000} {000000} {000000} {000001}
byte[] byteData = Convert.FromBase64String(stringData); // {00000000}{00000000}{00000001}

BitArray bitData = new BitArray(byteData.Reverse().ToArray()); // {000000000000000000000001}


Console.WriteLine("byteData");
for(var i=0; i < byteData.Length; i++){ //bitData.Length is 32
    var bitValue = byteData[i];
    Console.WriteLine("{0} {1}", i, bitValue);
}

Console.WriteLine();
Console.WriteLine("bitData");
for(var i=0; i < bitData.Length; i++){ //bitData.Length is 32
    var bitValue = bitData[i];
    Console.WriteLine("{0} {1}", i, bitValue);
}

Run this example

Important note, i will start counting from the lest significant bit (the one currently 1) and go to the right. so your output will be true, false, ..., false, false not false, false ..., false, true. If you want it the other way throw another .Reverse().ToArray() on bitData.

Console.WriteLine();
Console.WriteLine("reversed");
var reversed = bitData.Cast<bool>().Reverse().ToArray();
for(var i=0; i < reversed.Length; i++){ //bitData.Length is 32
    var bitValue = reversed[i];
    Console.WriteLine("{0} {1}", i, bitValue);
}

Upvotes: 2

neo
neo

Reputation: 161

Hope this helps.

        string stringData = "AAAB"; 
        byte[] byteData = Convert.FromBase64String(stringData); 
        StringBuilder sb = new StringBuilder("{");

        BitArray ba = new BitArray(byteData);
        for (int i = 0; i < ba.Length; i++)
        {
            sb.Append(ba[i] ? "1" : "0");    //append 1 if true, 0 if false.

            if (((i + 1) % 8 == 0) && ((i + 1) < ba.Length))  //adds formatting
                sb.Append("}{");
        }

        sb.Append("}");
        Console.Write("Bytes:" + sb.ToString());
        Console.Read(); //pause

Upvotes: 0

Sean Skelly
Sean Skelly

Reputation: 1324

I once wrote an Extension Method to allow getting and setting individual bits within a byte; maybe this will help you.

public static class MyExtensions
{
    /// <summary>
    /// Sets an individual bit inside a byte, based on the bit number.
    /// </summary>
    /// <param name="aByte">The byte where a bit is to be changed.</param>
    /// <param name="bitNumber">The bit number to read (between 0 and 7).</param>
    /// <param name="value">The value to set the bit to.  0/False or 1/True.</param>
    /// <returns>A byte with the requested bit changed.</returns>
    /// <remarks>The bit number must be between 0 and 7, otherwise an ArgumentOutOfRangeException is thrown.</remarks>
    public static byte SetBit(this byte aByte, byte bitNumber, bool value)
    {
        if (bitNumber > 7) { throw new ArgumentOutOfRangeException("bitNumber", "bitNumber was > 7"); }

        // create a mask of zeros except for the bit we want to modify
        byte mask = 1;
        mask = (byte)(mask << bitNumber);

        if (value)
        {
            // use bitwise-inclusive-or operator to make sure the bit equals 1 (and nothing else is changed)
            aByte = (byte)(aByte | mask);
        }
        else
        {
            // grab the inverse of our original mask (all ones except our bit equals zero)
            mask = (byte)(byte.MaxValue - mask);

            // use bitwise-and operator to make sure our bit equals 0 (and nothing else is changed)
            aByte = (byte)(aByte & mask);
        }
        return aByte;
    }


    /// <summary>
    /// Returns the value of an individual bit from within a byte.
    /// </summary>
    /// <param name="aByte">The byte from which to return bit data.</param>
    /// <param name="bitNumber">The bit number to read (between 0 and 7).</param>
    /// <returns>The value inside the requested bit.  0/False or 1/True.</returns>
    /// <remarks>The bit number must be between 0 and 7, otherwise an ArgumentOutOfRangeException is thrown.</remarks>
    public static bool GetBit(this byte aByte, byte bitNumber)
    {
        if (bitNumber > 7) { throw new ArgumentOutOfRangeException("bitNumber", "bitNumber was > 7"); }

        // create a mask of zeros except for the bit we want to modify
        byte mask = 1;
        mask = (byte)(mask << bitNumber);

        // use bitwise-and operator with our mask; if we get a 1, our bit must have also been a 1
        return (aByte & mask) > 0;
    }

}   

To use:

        byte b = 128;
        b = b.SetBit(1, true);

        bool b0 = b.GetBit(0); // false
        bool b1 = b.GetBit(1); // true, because we set it
        bool b2 = b.GetBit(2); // false
        bool b3 = b.GetBit(3); // false
        bool b4 = b.GetBit(4); // false
        bool b5 = b.GetBit(5); // false
        bool b6 = b.GetBit(6); // false
        bool b7 = b.GetBit(7); // true, because we started with 128

Upvotes: 1

Related Questions