{"id":17008718,"url":"https://github.com/i-e-b/bitwiseserialiser","last_synced_at":"2026-01-03T20:09:28.019Z","repository":{"id":139824721,"uuid":"536562409","full_name":"i-e-b/BitwiseSerialiser","owner":"i-e-b","description":"Bitwise serialiser/deserialiser for dotnet. Handles endian and alignment issues","archived":false,"fork":false,"pushed_at":"2024-09-05T14:59:56.000Z","size":426,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-15T01:14:18.855Z","etag":null,"topics":["production-ready","working"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/i-e-b.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-14T12:14:50.000Z","updated_at":"2024-09-05T15:00:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"af369bd0-b0e4-4131-9a95-3fc86eb138ed","html_url":"https://github.com/i-e-b/BitwiseSerialiser","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/i-e-b/BitwiseSerialiser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FBitwiseSerialiser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FBitwiseSerialiser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FBitwiseSerialiser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FBitwiseSerialiser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/i-e-b","download_url":"https://codeload.github.com/i-e-b/BitwiseSerialiser/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-e-b%2FBitwiseSerialiser/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001866,"owners_count":26083197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["production-ready","working"],"created_at":"2024-10-14T05:29:05.995Z","updated_at":"2025-10-09T17:32:41.464Z","avatar_url":"https://github.com/i-e-b.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BitwiseSerialiser\n\nBitwise serialiser/deserialiser for dotnet. Handles endian and alignment issues.\n\nAlso contains various small helpers for byte stream formatting and display.\n\n## Use\n\n### Structures\n\nTo use, you need to create classes for your data structures, and include **fields**\n(not properties) to hold the binary data.\n\nDecorate the class with `[ByteLayout]` attribute, and each field in the class with\none of the BigEndian / LittleEndian / ByteString attributes.\n\nEach of the field attributes has an `order` parameter. There must be an unbroken\nsequence from `order: 0` up across **all** fields in the class.\n\n```csharp\n[ByteLayout]\npublic class MyByteStructure\n{\n    [BigEndian(bytes: 2, order: 0)]\n    public UInt16 StartMarker;\n    \n    [BigEndian(bytes: 3, order: 1)]\n    public UInt32 ThreeBytesBig;\n    \n    [LittleEndian(bytes: 3, order: 2)]\n    public UInt32 ThreeBytesSmall;\n    \n    [LittleEndian(bytes: 2, order: 3)]\n    public UInt16 EndMarker;\n}\n```\n\nThe serialisers will ignore properties. This is intentional, so that properties\ncan represent the code-side typed data (including any conversions)\n\n### Serialisation and Deserialisation\n\nTo get a byte array from a data structure, use\n\n```csharp\nbyte[] data = ByteSerialiser.ToBytes(myClass);\n```\n\nTo restore a data structure from a byte array, use\n\n```csharp\nbyte[] data = ...\nvar ok = ByteSerialiser.FromBytes\u003cMyByteLayoutClass\u003e(data, out var resultingClass);\n```\n\nThe returned `ok` value will be `true` if the serialiser read the supplied number of bytes **or less**.\n`ok` will be false if the structure required more bytes than were supplied.\n\n### Attributes\n\n#### [ByteLayout]\nclass: no parameters\n\nAll classes in a structure used by the `ByteSerialiser` should be\nmarked with this attribute.\n\n#### [BigEndian]\nfield: bytes, order\n\nRepresents an unsigned integer value, taking the given number of bytes (1..8),\nMost Significant Byte first.\nCan handle non standard byte counts (e.g. 3 bytes into a UInt32).\nThe field type must be large enough to hold the value, and be one of\nbyte, UInt16, UInt32, UInt64, Int16, Int32, Int64.\n\n```csharp\n[ByteLayout]\npublic class SimpleByteStructure\n{\n    [BigEndian(bytes: 2, order: 0)]\n    public UInt16 TwoByteValue;\n}\n```\n\nNote that BigEndian and LittleEndian values can be mixed inside a structure.\n\n#### [LittleEndian]\nfield: bytes, order\n\nRepresents an unsigned integer value, taking the given number of bytes (1..8),\nLeast Significant Byte first.\nCan handle non standard byte counts (e.g. 3 bytes into a UInt32).\nThe field type must be large enough to hold the value, and be one of\nbyte, UInt16, UInt32, UInt64, Int16, Int32, Int64.\n\n```csharp\n[ByteLayout]\npublic class SimpleByteStructure\n{\n    [LittleEndian(bytes: 2, order: 0)]\n    public UInt16 TwoByteValue;\n}\n```\n\nNote that BigEndian and LittleEndian values can be mixed inside a structure.\n\n#### [BigEndianPartial]\nfield: bits, order\n\nRepresents an unsigned integer value, taking the given number of BITS (1..64),\nMost Significant Byte first.\nCan handle non standard bit counts (e.g. 13 bits into a UInt16)\n\nA sequence of BigEndianPartial attributes should line up to a byte boundary.\nIt is not required, but subsequent byte access will be unaligned, and slower.\n\nThere is no little-endian variant of this attribute\n\n```csharp\n[ByteLayout]\npublic class OneByteStructure\n{\n    [BigEndianPartial(bits:3, order: 0)]\n    public byte FirstThreeBits;\n    \n    [BigEndianPartial(bits:2, order: 1)]\n    public byte MiddleTwoBits;\n    \n    [BigEndianPartial(bits:3, order: 1)]\n    public byte LastThreeBits;\n}\n```\n\n#### [ByteString]\nfield: bytes, order\n\nRepresents a known-length list of bytes in input order\n\nThe field type must be `byte[]`, and the array is read and written in stream order.\n\n```csharp\n[ByteLayout]\npublic class FixedArrayStructure\n{\n    [ByteString(bytes: 5, order: 0)]\n    public byte[] MyArray;\n}\n```\n\n#### [RemainingBytes]\nfield: order\n\nRepresents an unknown length list of bytes in input order,\nfrom the current position to the end of input.\n\nThis should be the last field by order.\nDuring serialisation, this is treated as a normal byte string.\n\n```csharp\n[ByteLayout]\npublic class RemainingBytesStructure\n{\n    [BigEndian(bytes: 2, order: 0)]\n    public int SomethingElse;\n    \n    [RemainingBytes(order: 1)]\n    public byte[]? VariableArray;\n}\n```\n\n#### [VariableByteString]\nfield: source, order\n\nRepresents a list of bytes in input order, whose length is generated by a named function of the type.\n\nThe function should be a public instance method that takes no parameters and returns an int.\nThe function is allowed to return zero or negative values, which will be interpreted as empty.\nThe resulting byte array will be non-null and zero length.\n\nWhen based on another field, that field MUST be in earlier order than the variable byte string.\n\n```csharp\n[ByteLayout]\npublic class VariableArrayStructure\n{\n    [BigEndian(bytes: 2, order: 0)]\n    public int Length;\n    \n    [VariableByteString(source: nameof(GetLength), order: 1)]\n    public byte[] Variable = Array.Empty\u003cbyte\u003e();\n    \n    public int GetLength()=\u003eLength;\n}\n```\n\n#### [ValueTerminatedByteString]\nfield: stopValue, order\n\nRepresents a variable length list of bytes in input order.\nThe string ends when the given byte is reached.\nThe value read **includes** this byte.\n\nFor example, with a `StopValue` of `0x00`, this will read a C-style null-terminated character string.\n\n```csharp\n[ByteLayout]\npublic class NullTerminatedStringStructure\n{\n    [ValueTerminatedByteString(stopValue: 0x00, order: 1)]\n    public byte[]? MessageString;\n    \n    [BigEndian(bytes: 2, order: 2)]\n    public int Checksum;\n}\n```\n\n#### [FixedValueAttribute]\nfield: value\n\nMarks the field as having a fixed value.\nThe field **must** also have a `BigEndian` or `LittleEndian` attribute\n\n```csharp\n[ByteLayout]\npublic class SimpleByteStructure\n{\n    [BigEndian(bytes: 2, order: 0), FixedValue(0x7F, 0x80)]\n    public UInt16 StartMarker;\n}\n```\n\n#### [ByteLayoutChild]\nfield: order\n\nInclude a sub-structure into this structure.\n\n```csharp\n[ByteLayout]\npublic class ParentWithChild\n{\n    [ByteLayoutChild(order: 0)]\n    public OtherStructure ChildStruct;\n}\n```\n\nMarks a field as a substructure. The field type should be another class which\nis a `[ByteLayout]`. To repeat multiple times, see `[ByteLayoutMultiChild]` or `[ByteLayoutVariableChild]`\n\nChild structures can be nested to arbitrary depth.\n\n#### [ByteLayoutMultiChild]\nfield: count, order\n\nInclude a fixed number of sub-structures into this structure.\n\n```csharp\n[ByteLayout]\npublic class ParentWithRepeatedChild\n{\n    [ByteLayoutMultiChild(count: 3, order: 0)]\n    public OtherStructure[]? ChildStruct;\n}\n```\n\nMarks a field as a substructure. The field type should be an array of\nanother class which is a `[ByteLayout]`.\nSee also `[ByteLayoutChild]` or `[ByteLayoutVariableChild]`\n\nChild structures can be nested to arbitrary depth.\n\n#### [ByteLayoutVariableChild]\nfield: source, order\n\nInclude a variable number of sub-structures into this structure.\n`source` should be the name of a method **in this class** that will give\nthe number of repetitions required.\n\n```csharp\n[ByteLayout]\npublic class ParentWithVariableRepeatChild\n{\n    [BigEndian(bytes: 2, order:0)]\n    public int HowMany;\n    \n    [ByteLayoutVariableChild(nameof(CountHowMany), order: 1)]\n    public OtherStructure[]? ChildStruct;\n\n    public int CountHowMany() =\u003e HowMany;\n}\n```\n\nMarks a field as a substructure. The field type should be an array of \nanother class which is a `[ByteLayout]`.\nSee also `[ByteLayoutChild]` or `[ByteLayoutMultiChild]`\n\nChild structures can be nested to arbitrary depth.\n\n## Helpers\n\n### BCD conversions\n\n```csharp\nAssert.That(34.DecToBcd(), Is.EqualTo(0x34));\n\nvar ok = ((byte)0x34).BcdToDec(out var dec);\nAssert.That(ok, Is.True);\nAssert.That(dec, Is.EqualTo(34));\n```\n\n### Human Readable Binary Sizes\n\n```csharp\nAssert.That(1000000ul.Human(), Is.EqualTo(\"976.56kb\"));\nAssert.That(1073741824ul.Human(), Is.EqualTo(\"1gb\"));\n```\n\n### Byte array to C# code\n\n```csharp\nvar sample = new byte[] { 1, 2, 3, 100, 200, 255, 0 };\nAssert.That(sample.ToCsharpCode(\"myName\"), Is.EqualTo(\n    \"var myName = new byte[] {0x01, 0x02, 0x03, 0x64, 0xC8, 0xFF, 0x00};\"));\n```\n\n### Byte array to Hex View\n\n```csharp\nvar sample = new byte[] {\n    1,   2,   3,   4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,\n    17,  18,  19,  20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,\n    255, 255, 255, 0\n};\n\nAssert.That(sample.Describe(\"name of thing\"), Is.EqualTo(\n    \"name of thing =\u003e 36bytes\\r\\n\" +\n    \"0000: 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 \\r\\n\" +\n    \"0016: 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 \\r\\n\" +\n    \"0032: FF FF FF 00 \\r\\n\"));\n```\n\n### Byte to Binary String\n\n```csharp\nAssert.That(((byte)0xAA).ToBinString(), Is.EqualTo(\"10101010\"));\nAssert.That(((byte)0x55).ToBinString(), Is.EqualTo(\"01010101\"));\n```\n\n### Converting between Byte Arrays and Hex Strings\n\nNote: For dotnet 5+, you can use the built-in `Convert.ToHexString()` and `Convert.FromHexString()`.\n\n```csharp\nvar original = new byte[] {\n    1,2,4,8,16,32,64,128,255,127,63,31,15,7,3,1,0\n};\n\nvar hexStr = original.ToHexString();\nAssert.That(hexStr, Is.EqualTo(\"0102040810204080FF7F3F1F0F07030100\"));\n\nvar result = hexStr.ParseBytes();\nAssert.That(result, Is.EqualTo(original).AsCollection);\n```\n\n[END]","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi-e-b%2Fbitwiseserialiser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fi-e-b%2Fbitwiseserialiser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi-e-b%2Fbitwiseserialiser/lists"}