Bodu.Text.Bencode
1.3.0
dotnet add package Bodu.Text.Bencode --version 1.3.0
NuGet\Install-Package Bodu.Text.Bencode -Version 1.3.0
<PackageReference Include="Bodu.Text.Bencode" Version="1.3.0" />
<PackageVersion Include="Bodu.Text.Bencode" Version="1.3.0" />
<PackageReference Include="Bodu.Text.Bencode" />
paket add Bodu.Text.Bencode --version 1.3.0
#r "nuget: Bodu.Text.Bencode, 1.3.0"
#:package Bodu.Text.Bencode@1.3.0
#addin nuget:?package=Bodu.Text.Bencode&version=1.3.0
#tool nuget:?package=Bodu.Text.Bencode&version=1.3.0
Bodu.Text.Bencode
API stability - Stable. The public API surface is committed: breaking changes are reserved for a major-version bump per SemVer, except a deliberate break that is recorded in the release notes and in the package's
CompatibilitySuppressions.xml. See versioning and support.
A Bencode (BEP 3) serializer for .NET 8 and .NET 10. It maps plain CLR objects to and from Bencode through a configurable converter model, over a low-level, forward-only token reader and writer.
Installation
dotnet add package Bodu.Text.Bencode
Targets net8.0 and net10.0.
API shape
The public surface layers a high-level serializer, two document object models, and a low-level token reader/writer pair:
| Type(s) | Namespace | Role |
|---|---|---|
BencodeSerializer |
Bodu.Text.Bencode |
Static entry point: Serialize / Deserialize between CLR objects and Bencode. |
BencodeSerializerOptions |
Bodu.Text.Bencode |
Serializer configuration: converters, naming policy, ignore conditions, depth. |
Utf8BencodeReader / Utf8BencodeWriter |
Bodu.Text.Bencode.Reader / Bodu.Text.Bencode.Writer |
Forward-only, allocation-free ref struct token reader and writer. |
BencodeTokenType |
Bodu.Text.Bencode |
Classifies the token the reader is positioned on. |
NamingPolicy |
Bodu.Text.Serialization |
Converts member names to wire keys (for example camel case). |
BencodeConverter<T> / BencodeConverterFactory |
Bodu.Text.Bencode.Serialization |
Custom per-type read/write logic plugged into the serializer. |
[PropertyName] / [Ignore] |
Bodu.Text.Serialization |
Per-member attributes controlling wire names and inclusion. |
BencodeDocument / BencodeElement |
Bodu.Text.Bencode.Document |
Read-only, low-allocation document object model. |
BencodeNode / BencodeObject / BencodeArray / BencodeValue |
Bodu.Text.Bencode.Nodes |
Mutable document object model: parse, edit, write back. |
using Bodu.Text.Bencode;
byte[] payload = BencodeSerializer.Serialize(new TorrentInfo { Name = "ubuntu.iso", Length = 1024 });
TorrentInfo info = BencodeSerializer.Deserialize<TorrentInfo>(payload);
Serialize/Deserializeoverbyte[],ReadOnlySpan<byte>,IBufferWriter<byte>, andStream(synchronous and asynchronous), plusSerializeToNode,SerializeToDocument, andDeserialize(BencodeNode)bridges into the two DOMs.- Output is always canonical Bencode: dictionary entries are emitted in ascending bytewise key order, and the writer rejects duplicate keys and (by default) a second root value.
- Strings and
byte[]map to byte strings, the integer family toi…e, and enums to member-name byte strings. Types with no canonical Bencode form (Booleans, floating-point, date-times) require a registeredBencodeConverter<T>. Anullmember or dictionary value is omitted on write; anulllist element or root value cannot be written, because dropping it would shift every later element or leave no document, and throwsBencodeSerializationException. Utf8BencodeReaderandUtf8BencodeWriterexpose the low-level token surface directly for callers that do not want POCO mapping, includingValueTextEquals,CopyString,TokenStartIndex, the width-checked integer accessors,WriteRawValue, and the combined property-and-value overloads (writer.WriteInteger("length", 42)). By default the reader accepts only canonical BEP 3 (no leading or negative zeros, ascending unique dictionary keys, a single root with no trailing bytes).BencodeElement.GetRawBytes()returns a value's exact encoded slice - for example theinfodictionary of a torrent, whose SHA-1 is the info-hash - andWriteRawValuere-emits such slices verbatim.
Contracts and limits
Integers. BEP 3 integers are arbitrary-precision; this library supports the range [long.MinValue, ulong.MaxValue] on every surface. Values in (long.MaxValue, ulong.MaxValue] are readable through Utf8BencodeReader.GetUInt64, BencodeElement.GetUInt64, and GetValue<ulong>() on nodes, and writable through the ulong overload of WriteInteger and BencodeValue.Create(ulong); anything outside the supported range is rejected with BencodeFormatException. Arbitrary-precision (BigInteger) values are not supported.
Byte strings are bytes, not text. GetString accessors (reader, element, node) and string-typed members decode as UTF-8 and substitute U+FFFD for invalid sequences. Binding a binary field - such as a torrent's pieces - to a string silently corrupts it; map binary content to byte[] (or read ValueSpan / GetBytes), which is always lossless. Dictionary keys are byte strings too: Utf8BencodeReader reads any key exactly, as does BencodeDocument through BencodeProperty.GetNameBytes / NameEquals and the GetProperty(ReadOnlySpan<byte>) overloads, while the node tree and the serializer's dictionaries and extension data hold keys as text, so they refuse a key that is not valid UTF-8 (BencodeFormatException from BencodeNode.Parse, BencodeSerializationException from the serializer) rather than alter it.
Nesting depth. Utf8BencodeReader, Utf8BencodeWriter, BencodeDocument, and BencodeSerializerOptions.MaxDepth all default to a maximum depth of 64, which is also a hard ceiling: each can be configured lower, and a larger value is clamped to 64.
Single root. A Bencode document is a single value. The reader rejects empty input, which holds no value, and trailing bytes, and the writer rejects a second top-level value unless BencodeWriterOptions.AllowMultipleRootValues opts into concatenated-value framings.
Lenient reading of real-world documents. Older encoders occasionally emit unsorted or duplicate dictionary keys. AllowUnsortedKeys and AllowDuplicateKeys - available on BencodeReaderOptions, BencodeDocumentOptions, and BencodeSerializerOptions - relax those two rules independently while everything else stays strict. With duplicates permitted, the document model returns the first occurrence from name lookups (enumeration shows every pair), while the node tree and the serializer bind last-wins. Writing is always strict.
Exceptions. Failures are split by cause: BencodeFormatException (a FormatException, carrying the byte Offset) reports malformed input, and BencodeSerializationException reports values or documents that cannot be mapped. Catch both when handling should not distinguish the cause.
Property-name matching. BencodeSerializerOptions.PropertyNameCaseInsensitive defaults to true, so reads bind wire keys to members leniently. Wire keys themselves are raw bytes and case-sensitive; output never changes case. Under the default, two distinct keys that differ only in case (Name and name) bind to the same member, so a valid document carrying both is rejected with BencodeSerializationException as a duplicate member unless AllowDuplicateKeys is set (the later value then wins). Set PropertyNameCaseInsensitive to false to bind each key only to the member whose wire name matches it exactly.
Runnable samples
The repository ships an offline, dotnet run-able sample for this package - a real
BitTorrent metainfo file read, verified, and re-authored end to end (DOM inspection,
canonical byte-exact round trips, the raw-slice info-hash, typed POCO mapping) - under
samples/Text.Bencode/.
Building and testing
To build this package from source and run its tests, see CONTRIBUTING.md.
License
MIT. © Bodu Pty. Ltd.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Bodu.Core (>= 1.3.0)
- Bodu.Text.Serialization (>= 1.3.0)
-
net8.0
- Bodu.Core (>= 1.3.0)
- Bodu.Text.Serialization (>= 1.3.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Bodu.Text.Bencode:
| Package | Downloads |
|---|---|
|
Bodu.Extensions.Configuration.Text
The EditorConfig-compatible Microsoft.Extensions.Configuration provider. Bridges Bodu.Text.Configuration into the standard IConfiguration / IOptions<T> pipeline so a .boduconfig or bodu.config file registers with the same AddTextConfiguration(...) shape used for the JSON, INI, and XML providers - with file, stream, and programmatic-document overloads, reload-on-change, and colon-delimited section binding. Also ships the read-only TOML (AddTomlFile / AddTomlStream) and Bencode (AddBencodeFile / AddBencodeStream) sources. |
GitHub repositories
This package is not used by any popular GitHub repositories.