7

I have a fixed-length byte array that is 1250 bytes long. It may contain the following types of data:

  • Object A which consists of 5 bytes. The first byte contains the letter "A" and the next four bytes store an integer from 1 - 100000.

  • Object B which consists of 2 bytes. The first byte contains the letter "B" and the next byte contains an integer from 1 - 100.

  • Object C which consists of 50 bytes. All 50 bytes are used to store an ASCII-encoded string which will only consist of numbers and the following characters: - + ( and )

I don't know how many of each object type are in the byte array but I do know that they are grouped together (Object B, Object B, Object A, Object A, Object A, Object C, etc.). Most of the time when I parse a byte array, the array contains data of one type (all items are Object A, for example) so I know exactly how many bytes each item is comprised of and I just loop through the array processing the bytes. In this case, I have three different types of data that are all different lengths. I was thinking that I would need to do something like this:

int offset = 0;
while (offset <= 1250)
{
    string objectHeader = Encoding.ASCII.GetString(byteArray, offset, 1);

    if (objectHeader.Equals("A"))
    {
        // read 4 more bytes and then convert into int value (1 - 100000)
        index += 5;
    }
    else if (objectHeader.Equals("B"))
    {
        // read 1 more byte and then convert into int value (1 - 100)
        index += 2;
    }
    else
    {
        // read 49 more bytes and then convert into a string
        index += 50;
    }
}

Is there a better way of doing this?

7
  • 3
    What if the string enclosed in an instance of class C starts with a 'B' char? How will you know how to unpack it? You need to emit some sort of type information. Commented Feb 5, 2013 at 19:42
  • 3
    Is this information you are storing, or is this pre-existing data that you're trying to load? I ask because there are far easier ways to store data than byte arrays. Commented Feb 5, 2013 at 19:42
  • @Matt I failed to say that the string represented by Object C will only consist of numbers. If that were not the case, however, what kind of type information would you suggest? Commented Feb 5, 2013 at 19:52
  • 1
    Could you clarify: is there always 1250 bytes of meaningful 'data'? IE: You won't hit byte 1248 and find an 'A'? Otherwise, how do you know you're at the end of the data? You may end up with lots of redundant "Object Cs" otherwise. Commented Feb 5, 2013 at 20:04
  • 1
    Okay, thanks for that. And presumably your definition of 'null' is something you would parse as 'Object C' (doesn't start with ASCII letter 'A' or 'B') which didn't validate against your rules for the string above and/or try to overrun the buffer? Every solution looks fine here, I can't think of a better way of doing it. I was thinking you might be able to do something with StructLayout but it doesn't suit this case. Good luck with it. Commented Feb 5, 2013 at 20:20

2 Answers 2

9

Well, there seems to be a little confusion with offset and index, maybe you should be using a for-loop:

for(int index = 0; index < 1250; index++)
{
    switch(byteArray[index])
    {
         case (byte)'A':
             index++;
             int value = BitConverter.ToInt32(byteArray, index);
             index += 4;
             break;

       case (byte)'B':
             index++;
             // Read the next byte as integer.
             int value = (int)byteArray[index];
             index++;
             break;

       case (byte)'C':  // string.
             index++;
             // Read the next 49 bytes as an string.
             StringBuilder value = new StringBuilder(49);
             for(int i = index; i < index + 49; index++)
             {
                 if (byteArray[i] == 0) break;
                 value.Append(Converter.ToChar(byteArray[i]));
             }
             index+= 49;
             break;

       case 0:  // Finished.
             index = 1250;
             break;
       default:
             throw new InvalidArgumentException("Invalid byte array format");
    }
}

How do you see if there is no more objects? In my example I suggest it ends with a '\0'.

Good luck with your quest.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the suggestion. I have updated my original question to clarify that the string stored in Object C will only consists of numbers and the characters - + ( and )
I don't have a good way to know that there are no more objects without processing the whole byte array.
Presumably you don't have to parse the entire byte array because you will hit an object which doesn't match your format. EG: Object B, greater than 100; Object C, contains a character other than ASCII numbers and characters: - + ( and ). I'd imagine if this is a hardware device it will just pad it with 0x00s anyway so you'll hit a 50-character string which doesn't validate and break there.
3
      int offset = 0;
      while (offset <= 1250)
      {

        switch (byteArray[offset])
        {
          case (byte)'A':
            //read other data ..
            offset += 5;
            break;
          case (byte)'B':
            //read other data ..
            offset += 2;
            break;
          case (byte)'C':
            //read other data ..
            offset += 50;
            break;
          default:
            //error
            break;
        }
      } 

Or another variant with binary reader:

      var reader = new BinaryReader(new MemoryStream(byteArray), Encoding.ASCII);
      while (reader.BaseStream.Position < reader.BaseStream.Length)
      {
        switch(reader.ReadChar())
        {
          case 'A':
            {
              var i = reader.ReadInt32();
              return new TypeA(i);
            }
            break;
          case 'B':
            {
              var i = reader.ReadByte();
              return new TypeB(i);
            }
            break;
          case 'C':
            {
              var chars = reader.ReadChars(49);
              return new TypeC(new string(chars.TakeWhile(ch => ch != 0).ToArray()));
            }
            break;
        }

      }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.