using System.Collections.Generic;
public static void Main()
byte[] prefix = {0xDE, 0xAD, 0xBE, 0xEF};
byte[] block1 = {0xAA, 0xAA, 0xAA, 0xAA};
byte[] block2 = {0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, };
byte[] block3 = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
var data = BytePacker.Pack(prefix, block1, block2, block3);
Console.WriteLine($"Packed data ({data.Length} bytes):");
Console.WriteLine(string.Join(" ", data.Select(x => x.ToString("x2"))));
var blocks = BytePacker.Unpack(data, prefix.Length).ToArray();
Console.WriteLine(new string ('-', 79));
Console.WriteLine(" B# | Length | Data");
Console.WriteLine(new string ('-', 79));
for (int i = 0; i < blocks.Length; i++)
Console.Write($" {i:X2} | {blocks[i].Length, 5} B | ");
Console.WriteLine(string.Join(" ", blocks[i].Select(x => x.ToString("x2"))));
Console.WriteLine(new string ('-', 79));
Console.WriteLine($"{blocks.Sum(x => x.Length), 11} B total");
public static class BytePacker
public static byte[] Pack(byte[] prefix, params byte[][] blocks)
throw new ArgumentOutOfRangeException(nameof(blocks), "Minimum number of blocks is 2.");
throw new ArgumentOutOfRangeException(nameof(blocks), "Maximum number of blocks is 256.");
using (var ms = new System.IO.MemoryStream())
using (var bw = new System.IO.BinaryWriter(ms))
if (prefix != null && prefix.Length > 0)
bw.Write((byte)(blocks.Length - 1));
for (byte i = 0; i < blocks.Length - 1; i++)
if (blocks[i].Length > 255)
throw new ArgumentOutOfRangeException(nameof(blocks), $"Block #{i} is too long. Maximum length is 255 bytes.");
bw.Write((byte)blocks[i].Length);
for (byte i = 0; i < blocks.Length; i++)
public static IEnumerable<byte[]> Unpack(byte[] data, int prefixLength = 0)
throw new ArgumentOutOfRangeException(nameof(prefixLength));
using (var ms = new System.IO.MemoryStream(data))
using (var br = new System.IO.BinaryReader(ms))
yield return br.ReadBytes(prefixLength);
var numberOfBlocksExceptLast = ms.ReadByte();
var lengths = br.ReadBytes(numberOfBlocksExceptLast);
for (int i = 0; i < numberOfBlocksExceptLast; i++)
yield return br.ReadBytes(lengths[i]);
var bytesRead = prefixLength + 1 + numberOfBlocksExceptLast + lengths.Sum(x => x);
var lastBlockSize = data.Length - bytesRead;
yield return br.ReadBytes(lastBlockSize);