Ozgur Saklanmaz
Ozgur Saklanmaz

Reputation: 564

LINQ ile Array Splitting

I have a high size byte array. There are multiple packages in the array. It is unclear how many packages there are.

Package Structure => Header (0xAA 0xFE) + Lenght (2 Byte) + Data (Lenght Byte) + Checksum (2 Byte)

I want to split the packages inside the big array into separate arrays. The algorithm below does this. Is it possible to do this with LINQ?

What I want to learn is how we can control complex structures with LINQ.

Can you help if it can be done with LINQ? Thank you from now.

List<byte[]> allPacket = new List<byte[]>();

public void LogReadBuffer(byte[] buffer)
    {
        try
        {
            for(long i = 0; i < buffer.Length;)
            {
                if(buffer[i] == (char)0xAA && buffer[i+1] == 0xFE && Step == 0)
                {
                    Lenght = (short)(
                        ((byte)buffer[i + 2] << 8) +
                        ((byte)buffer[i + 3] << 0));

                    packet = new byte[Lenght + 6];

                    Step = 1;
                }

                else if(Step == 1)
                {
                    for (int packetCounter = 0; packetCounter < Lenght + 6; packetCounter++)
                    {
                        packet[packetCounter] = buffer[i++];
                    }

                    allPacket.Add(packet);
                    Step = 0;
                }
            }
        }

        catch { }
    }

Upvotes: 0

Views: 89

Answers (1)

NetMage
NetMage

Reputation: 26917

While I agree that built-in LINQ does not lend itself to irregular grouping, if you are willing to validate packages afterwards, or potentially have poorer error handling, an extension method makes for a simple LINQ statement.

This extension method groups data by using a method to determine the size of the next "chunk" of data, based on the data.

public static class LINQExt {
    // int ChunkSizeFn(T[] data, int start) - returns size of chunk at start
    public static IEnumerable<T[]> GroupByFunc<T>(this T[] data, Func<T[], int, int> ChunkSizeFn) {
        int offset = 0;
        while (offset < data.Length) {
            var currentChunkLen = ChunkSizeFn(data, offset);
            yield return new ArraySegment<T>(data, offset, currentChunkLen).ToArray();
            offset += currentChunkLen;
        }
    }
}

Using this extension method, you can pull out the chunks:

var allPackages = buffer.GroupByFunc((data,start) => (data[start+2] << 8) + data[start+3] + 6).ToList();

To filter to only packages with valid Headers, add a Where:

var allPackages = buffer
                    .GroupByFunc((data,start) => (data[start+2] << 8) + data[start+3] + 6)
                    .Where(p => p[0] == '\xAA' && p[1] == '\xFE')
                    .ToList();

Upvotes: 1

Related Questions