Skip to content

Instantly share code, notes, and snippets.

@ridercz
Last active March 5, 2018 09:58
Show Gist options
  • Save ridercz/b77c210cbb3bbe0b832b3a6d06a8ad86 to your computer and use it in GitHub Desktop.
Save ridercz/b77c210cbb3bbe0b832b3a6d06a8ad86 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program {
public static void Main() {
// Test data
byte[] prefix = { 0xDE, 0xAD, 0xBE, 0xEF }; // 4 bytes
byte[] block1 = { 0xAA, 0xAA, 0xAA, 0xAA }; // 4 bytes
byte[] block2 = { 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, }; // 8 bytes
byte[] block3 = { 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC }; // 16 bytes
// Pack
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"))));
Console.WriteLine();
// Unpack
var blocks = BytePacker.Unpack(data, prefix.Length).ToArray();
Console.WriteLine(new string('-', Console.WindowWidth - 1));
Console.WriteLine(" B# | Length | Data");
Console.WriteLine(new string('-', Console.WindowWidth - 1));
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('-', Console.WindowWidth - 1));
Console.WriteLine($"{blocks.Sum(x => x.Length),11} B total");
Console.WriteLine();
}
}
public static class BytePacker {
public static byte[] Pack(byte[] prefix, params byte[][] blocks) {
// Validate arguments
if (blocks.Length < 2) throw new ArgumentOutOfRangeException(nameof(blocks), "Minimum number of blocks is 2.");
if (blocks.Length > 256) throw new ArgumentOutOfRangeException(nameof(blocks), "Maximum number of blocks is 256.");
// Write structure
using (var ms = new System.IO.MemoryStream()) {
using (var bw = new System.IO.BinaryWriter(ms)) {
// Write prefix if any
if (prefix != null && prefix.Length > 0) bw.Write(prefix);
// Write number of blocks
bw.Write((byte)(blocks.Length - 1));
// Write block lengths
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);
}
// Write all blocks
for (byte i = 0; i < blocks.Length; i++) {
bw.Write(blocks[i]);
}
}
return ms.ToArray();
}
}
public static IEnumerable<byte[]> Unpack(byte[] data, int prefixLength = 0) {
if (prefixLength < 0) throw new ArgumentOutOfRangeException(nameof(prefixLength));
using (var ms = new System.IO.MemoryStream(data))
using (var br = new System.IO.BinaryReader(ms)) {
// Read prefix
if (prefixLength > 0) yield return br.ReadBytes(prefixLength);
// Get block lengths
var numberOfBlocksExceptLast = ms.ReadByte();
var lengths = br.ReadBytes(numberOfBlocksExceptLast);
// Read blocks except last
for (int i = 0; i < numberOfBlocksExceptLast; i++) {
yield return br.ReadBytes(lengths[i]);
}
// Read last block
var bytesRead = prefixLength + 1 + numberOfBlocksExceptLast + lengths.Sum(x => x);
var lastBlockSize = data.Length - bytesRead;
yield return br.ReadBytes(lastBlockSize);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment