{"id":15056413,"url":"https://github.com/ratopi/bencoding","last_synced_at":"2026-04-01T22:06:25.498Z","repository":{"id":57479585,"uuid":"154268991","full_name":"ratopi/bencoding","owner":"ratopi","description":"A fast encoder/decoder for the bittorrent data representation in pure Erlang","archived":false,"fork":false,"pushed_at":"2019-12-01T19:35:42.000Z","size":9,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-21T19:39:36.946Z","etag":null,"topics":["bencode","bencoding","bittorrent","bittorrent-protocol","erlang"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ratopi.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}},"created_at":"2018-10-23T05:43:13.000Z","updated_at":"2025-02-14T16:41:42.000Z","dependencies_parsed_at":"2022-09-18T06:04:36.506Z","dependency_job_id":null,"html_url":"https://github.com/ratopi/bencoding","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratopi%2Fbencoding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratopi%2Fbencoding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratopi%2Fbencoding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ratopi%2Fbencoding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ratopi","download_url":"https://codeload.github.com/ratopi/bencoding/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243532562,"owners_count":20306156,"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","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":["bencode","bencoding","bittorrent","bittorrent-protocol","erlang"],"created_at":"2024-09-24T21:51:01.082Z","updated_at":"2026-03-27T04:20:47.558Z","avatar_url":"https://github.com/ratopi.png","language":"Erlang","readme":"# bencoding\n\nAn encoder/decoder for the [Bencoding](https://www.bittorrent.org/beps/bep_0003.html) data format in pure Erlang.\n\nBencoding is the serialization format used by the [BitTorrent](https://www.bittorrent.org/) protocol\nfor torrent files and tracker communication.\n\n\n## Installation\n\n### Erlang (rebar3)\n\nAdd `bencoding` to your `deps` in `rebar.config`:\n\n```erlang\n{deps, [bencoding]}.\n```\n\n### Elixir (Mix)\n\nAdd `bencoding` to your `deps` in `mix.exs`:\n\n```elixir\ndefp deps do\n  [\n    {:bencoding, \"~\u003e 1.0\"}\n  ]\nend\n```\n\nSee [hex.pm/packages/bencoding](https://hex.pm/packages/bencoding) for the latest version info.\n\n\n## Type Mapping\n\nBencoding defines four data types. This library maps them to Erlang types as follows:\n\n| Bencoding Type | Erlang Type | Example (Bencoded) | Example (Erlang) |\n|---|---|---|---|\n| Integer | `integer()` | `i42e` | `42` |\n| Byte String | `binary()` | `4:spam` | `\u003c\u003c\"spam\"\u003e\u003e` |\n| List | `list()` | `l4:spami42ee` | `[\u003c\u003c\"spam\"\u003e\u003e, 42]` |\n| Dictionary | `map()` | `d3:cow3:mooe` | `#{\u003c\u003c\"cow\"\u003e\u003e =\u003e \u003c\u003c\"moo\"\u003e\u003e}` |\n\n**Notes:**\n- Bencoded strings are decoded as **binaries** (`\u003c\u003c...\u003e\u003e`), not as Erlang charlists.\n- Dictionary keys are always byte strings (binaries).\n- Dictionary keys are encoded in **sorted order** (sorted as raw strings, not alphanumerics), as required by BEP 3.\n- Encoding and decoding are **roundtrip-safe**: `decode(encode(Value))` yields the original value.\n\n\n## API\n\nThe library exports two functions:\n\n### `bencoding:encode/1`\n\nEncodes an Erlang term into a bencoded binary.\n\n```erlang\n%% Encode a string\n{ok, \u003c\u003c\"4:spam\"\u003e\u003e} = bencoding:encode(\u003c\u003c\"spam\"\u003e\u003e).\n\n%% Encode an integer\n{ok, \u003c\u003c\"i42e\"\u003e\u003e} = bencoding:encode(42).\n\n%% Encode a list\n{ok, \u003c\u003c\"l4:spam4:eggse\"\u003e\u003e} = bencoding:encode([\u003c\u003c\"spam\"\u003e\u003e, \u003c\u003c\"eggs\"\u003e\u003e]).\n\n%% Encode a dictionary (keys are automatically sorted)\n{ok, \u003c\u003c\"d3:cow3:moo4:spam4:eggse\"\u003e\u003e} = bencoding:encode(#{\n    \u003c\u003c\"spam\"\u003e\u003e =\u003e \u003c\u003c\"eggs\"\u003e\u003e,\n    \u003c\u003c\"cow\"\u003e\u003e =\u003e \u003c\u003c\"moo\"\u003e\u003e\n}).\n\n%% Encode an empty dictionary\n{ok, \u003c\u003c\"de\"\u003e\u003e} = bencoding:encode(#{}).\n\n%% Encode nested structures\n{ok, Encoded} = bencoding:encode(#{\n    \u003c\u003c\"name\"\u003e\u003e =\u003e \u003c\u003c\"example\"\u003e\u003e,\n    \u003c\u003c\"files\"\u003e\u003e =\u003e [\u003c\u003c\"a.txt\"\u003e\u003e, \u003c\u003c\"b.txt\"\u003e\u003e],\n    \u003c\u003c\"size\"\u003e\u003e =\u003e 1024\n}),\n\u003c\u003c\"d5:filesl5:a.txt5:b.txte4:name7:example4:sizei1024ee\"\u003e\u003e = Encoded.\n```\n\n**Returns:** `{ok, Binary}` on success.\n\n\n### `bencoding:decode/1`\n\nDecodes a bencoded binary into an Erlang term.\n\n```erlang\n%% Decode a string\n{ok, \u003c\u003c\"spam\"\u003e\u003e, \u003c\u003c\u003e\u003e} = bencoding:decode(\u003c\u003c\"4:spam\"\u003e\u003e).\n\n%% Decode an integer\n{ok, 42, \u003c\u003c\u003e\u003e} = bencoding:decode(\u003c\u003c\"i42e\"\u003e\u003e).\n\n%% Decode a list\n{ok, [\u003c\u003c\"spam\"\u003e\u003e, \u003c\u003c\"eggs\"\u003e\u003e], \u003c\u003c\u003e\u003e} = bencoding:decode(\u003c\u003c\"l4:spam4:eggse\"\u003e\u003e).\n\n%% Decode a dictionary\n{ok, #{\u003c\u003c\"cow\"\u003e\u003e := \u003c\u003c\"moo\"\u003e\u003e}, \u003c\u003c\u003e\u003e} = bencoding:decode(\u003c\u003c\"d3:cow3:mooe\"\u003e\u003e).\n```\n\n**Returns:** `{ok, Value, Rest}` on success, where `Rest` is the remaining (not yet decoded) binary data.\n\nThe `Rest` value is useful when decoding data that may have trailing content:\n\n```erlang\n{ok, 42, \u003c\u003c\"extra\"\u003e\u003e} = bencoding:decode(\u003c\u003c\"i42eextra\"\u003e\u003e).\n```\n\n\n## Error Handling\n\nThe decoder detects and rejects certain invalid inputs as defined by the Bencoding specification:\n\n```erlang\n%% Negative zero is not allowed\n{error, negative_zero} = bencoding:decode(\u003c\u003c\"i-0e\"\u003e\u003e).\n\n%% Leading zeros are not allowed\n{error, leading_zero} = bencoding:decode(\u003c\u003c\"i03e\"\u003e\u003e).\n{error, leading_zero} = bencoding:decode(\u003c\u003c\"i-03e\"\u003e\u003e).\n```\n\nOther malformed inputs (e.g. missing terminators, invalid characters) will result in\na `function_clause` error or a `badmatch` error.\n\n\n## Practical Example: Reading a Torrent File\n\n```erlang\n%% Read and decode a .torrent file\n{ok, FileContent} = file:read_file(\"example.torrent\"),\n{ok, Torrent, \u003c\u003c\u003e\u003e} = bencoding:decode(FileContent),\n\n%% Access the info dictionary\nInfo = maps:get(\u003c\u003c\"info\"\u003e\u003e, Torrent),\n\n%% Get the file name\nName = maps:get(\u003c\u003c\"name\"\u003e\u003e, Info),\nio:format(\"Torrent name: ~s~n\", [Name]),\n\n%% Get the announce URL\nAnnounce = maps:get(\u003c\u003c\"announce\"\u003e\u003e, Torrent),\nio:format(\"Tracker: ~s~n\", [Announce]).\n```\n\n\n## Using from Elixir\n\nThe library can be used directly from Elixir without any wrapper:\n\n```elixir\n# Encoding\n{:ok, encoded} = :bencoding.encode(\"spam\")\n# =\u003e {:ok, \"4:spam\"}\n\n# Encoding a map (keys are sorted automatically)\n{:ok, encoded} = :bencoding.encode(%{\"cow\" =\u003e \"moo\", \"spam\" =\u003e \"eggs\"})\n# =\u003e {:ok, \"d3:cow3:moo4:spam4:eggse\"}\n\n# Decoding\n{:ok, value, rest} = :bencoding.decode(\"d3:cow3:mooe\")\n# =\u003e {:ok, %{\"cow\" =\u003e \"moo\"}, \"\"}\n\n# Reading a torrent file\n{:ok, content} = File.read(\"example.torrent\")\n{:ok, torrent, \"\"} = :bencoding.decode(content)\nannounce = Map.get(torrent, \"announce\")\n\n# Error handling\n{:error, :negative_zero} = :bencoding.decode(\"i-0e\")\n{:error, :leading_zero} = :bencoding.decode(\"i03e\")\n```\n\n\n## Specification Compliance\n\nThis library follows the Bencoding specification as defined in\n[BEP 3: The BitTorrent Protocol Specification](https://www.bittorrent.org/beps/bep_0003.html):\n\n- Integers are encoded as `i\u003cinteger in base 10\u003ee`. Integers have no size limitation.\n- Byte strings are encoded as `\u003clength\u003e:\u003ccontents\u003e`\n- Lists are encoded as `l\u003celements\u003ee`\n- Dictionaries are encoded as `d\u003cpairs\u003ee` with keys sorted as raw strings (not alphanumerics), as required by BEP 3\n- Leading zeros in integers are rejected (`i03e` is invalid, `i0e` is valid)\n- Negative zero (`i-0e`) is rejected\n\n**Note for torrent client developers:** BEP 3 states that the info-hash\n(the SHA-1 hash of the bencoded `info` dictionary) must be computed from\nthe bencoded form as found in the `.torrent` file. Clients must\neither reject invalid metainfo files or extract the info substring directly.\nThey must not perform a decode-encode roundtrip on invalid data.\n\n\n## License\n\nMIT — see [LICENSE](LICENSE) for details.\n\n\n## Issues\n\nIf you find a bug or miss a feature, please open an issue:\nhttps://github.com/ratopi/bencoding/issues\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fratopi%2Fbencoding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fratopi%2Fbencoding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fratopi%2Fbencoding/lists"}