Click here to Skip to main content
15,907,906 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello.
I am hoping someone can point me in the right direction please.

I am new to C# and writing a simple application that uses a Data Grid to display a range of bytes read in from a file or smart card.

Each row on my Data Grid has an offset address, then 8x byte entries labelled 00, 01, 02 etc.

My custom class takes a byte[] input and loops through, taking 8x bytes at a time and building a <list> of my custom class byte blocks (this is just a class that represents a block of eight bytes and the offset so that I can loop through and add them to the Data Grid.

Now it works fine, providing I have a byte[] structure of a multiple of 8, however, lets say I have byte[18] - now I have 2x byte clocks of 8 bytes, plus 2x bytes left over.

I am trying to figure out how to create the third data block with the left over 2x bytes, and fill the remaining 6 bytes with 0x00, and this is where I am stuck.

I have tried googling but not sure what I am looking for so it is hard to find a solution.

I will try to show the code sections that I feel are relevant, and I would be very grateful if anyone could assist, but please take into consideration I am learning and know my code is likely to be messy :)

C#
<pre>private void BuildDataArray()
        {

            // TODO Need to re-write so that we can also create rows for odd number of byte left over, and set the rmaining bytes in that block to 0x00

            int dataSize = data.Length; // How many Bytes are in our full data block
            uint calcOffset = 0x00;

            int count = dataSize / 8; // Get a count of each 8 byte block
            int bytesToTake = 8;
            int bytesToSkip = 0;

            for (int i = 0; i < count; i++)
            {


                byte[] tempData = data.Skip(bytesToSkip).Take(bytesToTake).ToArray();

                bytesToSkip = bytesToSkip + 8;
                bytesToTake = bytesToTake + 8;

                ByteBlock tempByteBlock = new ByteBlock(tempData, calcOffset);

                calcOffset = calcOffset + 8;

                _byteBlock.Add(tempByteBlock); // Add each 8 byte block to the main ByteBlockArray

            }


        }



This is my ByteBlockArray class that holds an array of byte clocks, which in turn hold 8 byte blocks of data with an offset...

C#
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataTest
{
    class ByteBlockArray
    {
        private List<ByteBlock> _byteBlock = new List<ByteBlock>(); // Array/List of ByteBlock objects each to hold an 8 byte "recoord" for the datagrid


        private byte[] data; // This is the full data block that will be used to create 8xbyte blocks
        private byte offset; // This will hold the initial offset for the full data block



        public ByteBlockArray(byte[] data, byte offset)
        {
            this.data = data;
            this.offset = offset;


            BuildDataArray();

        }



        private void BuildDataArray()
        {

            // TODO Need to re-write so that we can also create rows for odd number of byte left over, and set the rmaining bytes in that block to 0x00

            int dataSize = data.Length; // How many Bytes are in our full data block
            uint calcOffset = 0x00;

            int count = dataSize / 8; // Get a count of each 8 byte block
            int bytesToTake = 8;
            int bytesToSkip = 0;

            for (int i = 0; i < count; i++)
            {


                byte[] tempData = data.Skip(bytesToSkip).Take(bytesToTake).ToArray();

                bytesToSkip = bytesToSkip + 8;
                bytesToTake = bytesToTake + 8;

                ByteBlock tempByteBlock = new ByteBlock(tempData, calcOffset);

                calcOffset = calcOffset + 8;

                _byteBlock.Add(tempByteBlock); // Add each 8 byte block to the main ByteBlockArray

            }


        }



        public ByteBlock GetByteBlockIndex(int index)
        {
            return _byteBlock[index];
        }

        public int GetByteBlockCount()
        {
            return this._byteBlock.Count;
        }
    }
}


This is the Byte Block class as described above, and this is the <list> of items that are displayed on my Data Grid...

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataTest
{
    class ByteBlock
    {
        
        private byte _00 = 0x00;
        private byte _01 = 0x00;
        private byte _02 = 0x00;
        private byte _03 = 0x00;
        private byte _04 = 0x00;
        private byte _05 = 0x00;
        private byte _06 = 0x00;
        private byte _07 = 0x00;
        private byte[] tempData;
        private uint calcOffset;

        public ByteBlock(byte[] tempData, uint calcOffset)
        {
            this.tempData = tempData;
            this.calcOffset = calcOffset;

            FillBytes();

        }

        public ByteBlock()
        {
        }

        private void FillBytes()
        {
            this._00 = tempData[0];
            this._01 = tempData[1];
            this._02 = tempData[2];
            this._03 = tempData[3];
            this._04 = tempData[4];
            this._05 = tempData[5];
            this._06 = tempData[6];
            this._07 = tempData[7];
        }




        public uint Offset
        {
            get { return calcOffset; }
        }

        public byte i00
        {
            get { return _00; }
        }

        public byte i01
        {
            get { return _01; }
        }

        public byte i02
        {
            get { return _02; }
        }

        public byte i03
        {
            get { return _03; }
        }

        public byte i04
        {
            get { return _04; }
        }

        public byte i05
        {
            get { return _05; }
        }

        public byte i06
        {
            get { return _06; }
        }

        public byte i07
        {
            get { return _07; }
        }

    }
}


And this is the code I use on the main form to test, passing in a dummy byte array. If the byte array is in multiples of 8 bytes it works fine, if not it wont work as is...

C#
<pre>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DataTest
{
    public partial class Form1 : DevExpress.XtraEditors.XtraForm
    {

        List<ByteBlock> dataStructure = new List<ByteBlock>();

        public Form1()
        {
            InitializeComponent();
        }



        private void ButtonCreateData_Click(object sender, EventArgs e)
        {

            byte[] data = {0xed, 0xc6, 0x43, 0x32, 0x45, 0xd3, 0x3a, 0x43, 0xed, 0xc6, 0x43, 0x32, 0x45, 0xd3, 0x3a, 0x43};

            ByteBlockArray byteArray = new ByteBlockArray(data, 0x00);



            // CAUTION! TEMP area to load data to grid, need to move this to correct place and change as required


            int count = byteArray.GetByteBlockCount();
            ByteBlock bblock = new ByteBlock();


            for (int i = 0; i < count; i++)
            {
                bblock = byteArray.GetByteBlockIndex(i);

                // Now add data/rows to grid
                // outputTokenView.Items.Add(new ListViewItem(new string[] { tkn.GetSerialAsString(), tkn.GetSeedAsString(), tkn.GetKeyAsString(), tkn.GetCreationDate(), tkn.GetExpiryDaysAsString(), tkn.GetStateAsString(), tkn.GetSignatureAsString() }));

                dataStructure.Add(bblock);
                
            }

            gridControl1.DataSource = dataStructure;

        }


    }
}


Also, just to point out, I am using the Data Grid control from DevExpress Winforms subscription.

Again, thank you very much for any help...

What I have tried:

Found out everything so far from my learning books and Google but unable to find out how to get past this point as not even sure what I am searching for.

Thanks
Posted
Updated 26-Dec-18 6:54am

Basic input / output logic uses "buffers" that can hold the maximum amount of "data" read / written.

Simply take your "variable" data and load it into a "buffer" that is some multiple of 8 then chunk through it. You obviously need to track the length of the "actual" data in the buffer.
 
Share this answer
 
The logic is fairly straightforward:
byteArray = // input data
numberOfBytes = // length of input data
blockSize = 8
offset = 0
WHILE numberOfBytes > 0
DO
    copybytes(byteArray[offset], destinationAddress, blocksize) // copy a block
    offset += blockSize                                         // increment the offset
    numberOfBytes -= blockSize                                  // decrement the number remaining
    if numberOfBytes < blockSize    // if remainder is less than the blocksize
        blockSize = numpberOfBytes  // set the blocksize to remainder for last block
DONE
 
Share this answer
 
Comments
Member 14097984 23-Dec-18 11:34am    
Thank you for the answers, however, the logic shown above was exactly what I needed, thanks.

Can I just ask, do you think my set up for what I am trying to achieve seems OK, or is it a bit too complicated (trying to get head around the object oriented way).

My class structure is basically.

1. Byte class - holds a byte, its address and properties (e.g this is a protected byte)
2. Byte Block Class - this holds an 8 byte of the above, along with the offset address
3. ByteBlockArray Class - an array of Byte Block objects, with the methods to create each 8 byte block from the raw data[]
4. ByteDataClass - this is just a custom class with public get/set for each component in the Byte Block class, used to bind to my Data Grid and display the data.

Going with the above design, things seem to work OK, however, I cant help but feel it may be over complected for its intended purpose, which ultimately is to take a byte[] of any length and display rows of 8 bytes and the offset on a data grid, just like a standard hex display.

Anyway, thanks again! :)
Stephen
Richard MacCutchan 23-Dec-18 11:57am    
I would guess that is a bit too complicated. I would use a single class that can be initialised with a block (i.e. an array) of bytes, and can then return it in blocks of 8 bytes. I am not sure what you mean by a protected byte or how you recognise one.
Member 14097984 23-Dec-18 14:03pm    
Hi Richard, thank you.

A protected byte is one that has been protected (made read only) in my memory smart card, so by having a property that marks a byte as protected, I can display the byte in a different colour in my Data Grid.

If I went with just one class as you suggested, should I still create my class to hold the information to display in my Data Grid, as this needs a <list> class to bind as the data source, and then I could set its properties from my main data block class, or do you recommend building this into the one class and having that the source of 8 bytes, and sending the data for the grid?

Thanks again.
Stephen
Richard MacCutchan 24-Dec-18 4:33am    
If some bytes are protected then you need some way to identify that property, which may be an extra class.
The class that holds the data needs to provide the methods that allow it to be bound to the datagrid. The documentation on MSDN explains how to do this.
Member 14097984 23-Dec-18 17:16pm    
Also one last thing, if I go with your suggestion, how would I get the class to return blocks of 8 bytes for my data grid. For example, if I have the one class that I pass in a data[16], and this is a <list> bound to my data grid, how would I get this class to return the 2x blocks of 8 bytes for the grid? Hope that makes sense, sorry, still learning :) thanks again, Stephen.
Create a class that can return the data 8-bytes at a time, by implementing the IEnumerable interface, something like:
C#
using System;
using System.Collections;


public class Bytes : IEnumerable
{
    private Byte[] _bytes;
    // create the internal byte block from the array passed in
    public Bytes(Byte[] pArray)
    {
        _bytes = new Byte[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _bytes[i] = pArray[i];
        }
    }

    // Implementation for the GetEnumerator method.
    IEnumerator IEnumerable.GetEnumerator()
    {
        return (IEnumerator)GetEnumerator();
    }

    public ByteEnum GetEnumerator()
    {
        return new ByteEnum(_bytes);
    }
}

// When you implement IEnumerable, you must also implement IEnumerator.
public class ByteEnum : IEnumerator
{
    public Byte[] _bytes;

    // Enumerators are positioned before the first element
    // in this case an element is an 8-byte block
    // until the first MoveNext() call.
    int offset = -8;
    int remainder = 0;  // number of bytes remining to be copied

    // create a new enumerator
    public ByteEnum(Byte[] list)
    {
        _bytes = list;
        remainder = _bytes.Length;
    }

    // move to the next 8-byte block
    public bool MoveNext()
    {
        offset += 8;
        // this returns true if more data, false if not
        // and controls the action of the foreach statement
        return (remainder > 0);
    }

    // restart at the beginning of the data
    public void Reset()
    {
        offset = -8;
        remainder = _bytes.Length;
    }

    // returns the current 8-byte block
    object IEnumerator.Current
    {
        get
        {
            return Current;
        }
    }

    public Byte[] Current
    {
        get
        {
            try
            {
                // allocate a new 8-byte block and copy the next
                // group of 8-bytes from the source
                Byte[] newbytes = new byte[8];
                int count = remainder > 8 ? 8 : remainder;
                Array.Copy(_bytes, offset, newbytes, 0, count);
                // reduce the number still to copy
                remainder -= 8;
                return newbytes;
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}


class App
{
    static void Main()
    {
        Bytes data = new Bytes(new byte[] { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 });
        foreach (Byte[] ba in data)
            Console.WriteLine(String.Format("{0} {1} {2} {3} {4} {5} {6} {7} ", (char)ba[0], (char)ba[1], (char)ba[2], (char)ba[3], (char)ba[4], (char)ba[5], (char)ba[6], (char)ba[7]));
        Console.ReadLine();
    }
}

Note that you may need to adjust the ByteEnum.Current() method to return the bytes as printable characters.
 
Share this answer
 
Comments
Member 14097984 27-Dec-18 13:38pm    
Perfect. Thank you very much for all your help and support, it has been greatly appreciated, and I have learnt one or two things.

Thanks
Stephen
Richard MacCutchan 28-Dec-18 3:56am    
Happy to help, good luck.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900