Created
December 8, 2025 01:11
-
-
Save iwconfig/b973c8c7a974a94f114cd96337eb2280 to your computer and use it in GitHub Desktop.
bencode decoder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import sys | |
| import json | |
| def bdecode(bencoded_bytes): | |
| def decode_int(b, i): | |
| j = b.find(b'e', i) | |
| return int(b[i:j]), j + 1 | |
| def decode_bytes(b, i): | |
| colon = b.find(b':', i) | |
| length = int(b[i:colon]) | |
| start = colon + 1 | |
| return b[start:start+length], start+length | |
| def decode_list(b, i): | |
| items = [] | |
| i += 1 | |
| while b[i:i+1] != b'e': | |
| value, i = decode_element(b, i) | |
| items.append(value) | |
| return items, i + 1 | |
| def decode_dict(b, i): | |
| items = {} | |
| i += 1 | |
| while b[i:i+1] != b'e': | |
| key, i = decode_bytes(b, i) | |
| value, i = decode_element(b, i) | |
| items[key] = value | |
| return items, i + 1 | |
| def decode_element(b, i): | |
| if b[i:i+1] == b'i': | |
| return decode_int(b, i+1) | |
| elif b[i:i+1] == b'l': | |
| return decode_list(b, i) | |
| elif b[i:i+1] == b'd': | |
| return decode_dict(b, i) | |
| elif b[i:i+1].isdigit(): | |
| return decode_bytes(b, i) | |
| else: | |
| raise ValueError("Invalid bencode format") | |
| decoded_data, _ = decode_element(bencoded_bytes, 0) | |
| return decoded_data | |
| def convert_bytes_to_str(data): | |
| """Recursively converts bytes keys and values in a dict/list to UTF-8 strings.""" | |
| if isinstance(data, bytes): | |
| try: | |
| # Assume UTF-8 encoding for standard torrent metadata (filenames, etc.) | |
| return data.decode('utf-8') | |
| except UnicodeDecodeError: | |
| # Handle non-UTF-8 data gracefully (maybe represent as hex or just skip) | |
| return data.hex() | |
| elif isinstance(data, list): | |
| return [convert_bytes_to_str(item) for item in data] | |
| elif isinstance(data, dict): | |
| new_dict = {} | |
| for key, value in data.items(): | |
| # Convert both the key (which is currently a bytes object) | |
| # and the value recursively | |
| new_key = convert_bytes_to_str(key) | |
| new_value = convert_bytes_to_str(value) | |
| new_dict[new_key] = new_value | |
| return new_dict | |
| else: | |
| # Handle integers or other types | |
| return data | |
| raw_bencode_response = sys.stdin.buffer.read() | |
| decoded_info = bdecode(raw_bencode_response) | |
| # Convert all bytes to strings recursively | |
| decoded_info_str = convert_bytes_to_str(decoded_info) | |
| # Safely remove the "pieces" key now that keys are strings | |
| if "pieces" in decoded_info_str: | |
| del decoded_info_str["pieces"] | |
| # Dump the fully stringified dictionary to stdout as JSON | |
| print(json.dumps(decoded_info_str, indent=2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment