Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace two bytes in a generic list

Tags:

c#

.net

I want to replace every occurrence of one of those magic 2-byte packages in my List<byte> with a single byte:

{ 0xF8, 0x00 } -> Replace with 0xF8
{ 0xF8, 0x01 } -> Replace with 0xFB
{ 0xF8, 0x02 } -> Replace with 0xFD
{ 0xF8, 0x03 } -> Replace with 0xFE

For example:

List<byte> message 
    = new List<byte> { 0xFF, 0xFF, 0xFB, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x02, 0xF8, 0x03, 0xFE };

// will be converted to:

List<byte> expected 
    = new List<byte> { 0xFF, 0xFF, 0xFB, 0xF8, 0xFB, 0xFD, 0xFE, 0xFE };

This is my solution so far, which works but I don't like it because its readability is quite bad:

public static void RemoveEscapeSequences(List<byte> message)
{
    // skipped parameter checks
    for (int index = 0; index < message.Count - 1; ++index)
    {
        if (message[index] == 0xF8)
        {
            // found an escaped byte, look at the following byte to determine replacement
            switch (message[index + 1])
            {
                case 0x0:
                    message[index] = 0xF8;
                    message.RemoveAt(index + 1);
                    break;
                case 0x1:
                    message[index] = 0xFB;
                    message.RemoveAt(index + 1);
                    break;
                case 0x2:
                    message[index] = 0xFD;
                    message.RemoveAt(index + 1);
                    break;
                case 0x3:
                    message[index] = 0xFE;
                    message.RemoveAt(index + 1);
                    break;
            }
        }
    }
}       

Is there a shorter solution with improved readability?

like image 312
nabulke Avatar asked Mar 15 '13 12:03

nabulke


2 Answers

You can do something like this - it'll be slightly slower, though:

public static void RemoveEscapeSequences(List<byte> message)
{
    var replaceBytes = new Dictionary<byte, byte>()
    {
        {0x00, 0xF8}, {0x01, 0xFB}, {0x02, 0xFD}, {0x03, 0xFE}
    };

    // skipped parameter checks
    for (int index = 0; index < message.Count - 1; ++index)
    {
        if (message[index] == 0xF8)
        {
            if(replaceBytes.ContainsKey(message[index + 1]))
            {
                message[index] = replaceBytes[message[index + 1]];
                message.RemoveAt(index + 1);
            }
        }
    }
}  
like image 94
Dave Bish Avatar answered Sep 28 '22 06:09

Dave Bish


You can use following extension method:

public static IEnumerable<byte> Escape(this IEnumerable<byte> source)
{
    if (source == null)     
        throw new ArgumentNullException("source");

    using (var enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            byte current = enumerator.Current;

            if (current != 0xF8)
            {
                yield return current;
                continue;
            }

            if (!enumerator.MoveNext())
                yield return current;

            byte next = enumerator.Current;

            switch (next)
            {
                case 0x00: yield return 0xF8; break;
                case 0x01: yield return 0xFB; break;
                case 0x02: yield return 0xFD; break;
                case 0x03: yield return 0xFE; break;
                default:
                    yield return current;
                    yield return next;
                    break;
            }
        }
    }
}

Usage:

List<byte> result = message.Escape().ToList();

foreach(var b in message.Escape())
     Console.Write("0x{0:x} ", b);
like image 32
Sergey Berezovskiy Avatar answered Sep 28 '22 06:09

Sergey Berezovskiy