Here’s something I’ve wasted a couple of days on to get right; a BEncoding utility class that encodes/decodes data to and from bencoded bytes, written in Objective-C, as specified in the BitTorrent Specification.
I don’t think I’ll have time to write an entire bittorrent client, but at least here’s a GPL’d class you could use in your own client or tool :) If you want to use this in a commercial product, then please contact me and I’ll be happy to provide you with an appropriately licensed version.
Instructions
It’s pretty straight forward. If you have a bencoded byte array in a NSData object called data, you can retrieve a pointer to the decoded object(s) by calling [BEncoding objectFromEncodedData:data].
It will deserialise NSDictionary, NSArray, NSNumber and NSData objects from a given bencoded byte array, and will of course handle nested objects, so an encoded array can have each entry holding a dictionary, which in turn holds string keys and number values.
Strings are always returned as NSData objects, except when they are used as keys to NSDictionary objects. Its up to you to convert the NSData to an NSString, as there is no hint that a given byte string is actually a string and not a chunk of binary data. The exception to this is that any NSString used as a key is decoded as a UTF8 string.
If you have an NSString, NSData, NSNumber, NSArray or NSDictionary, you can serialise them to a bencoded byte array by calling [BEncoding encodedDataFromObject:object]. NSStrings are encoded as UTF8 strings. Collections of course recursively encode their contents. Unsupported types are ignored.
Notes
This is an exercise in using Obj-C Foundation types for doing as much of the heavy lifting as possible. It may not be as efficient as an equivalent C implementation, however for Obj-C programmers, it might be ‘good enough’. If you have any patches that improve performance or fixes a bug, mail them to be and I’ll check them out.
Download: BEncoding-1.0.0.zip
Hi
Just wanted to say thanks for writing this class and posting the source code. As someone who’s just gotten started on ObjC and Cocoa programming, I found it a very useful class for viewing bencoded data from torrents I had downloaded. I did find two limitations that users of this class might find useful to know about in advance:
Sometimes bencoded dictionaries have binary keys – for example, if you query a tracker about a torrent (you would do this to find out how many seeds and leachers the torrent had), the reply you get includes a dictionary where a binary key (info_hash) is used to identify the torrent. Since the class codes dictionary keys as NSStrings, such dictionaries can’t be parsed by the class.
I found it difficult to use the class when I wanted to calculate the info_hash for a torrent file. The class returns dictionaries as NSDictionaries, so as far as I am aware, there is no way to determine the order in which the keys in the dictionary were encoded. But this is important when calculating a hash. This is something which I imagine a reasonable proportion of people interested in bencoding might want to do.
I havn’t had time to actually use my class in a practical application, so your comments are useful. I’ll have a think about it and post an update when I have time.
According to the specification (BEP3) the keys in a dictionary should always be sorted (as raw strings). So the order of the keys in a dictionary is fixed, and this shouldn’t give any issues when encoding a dictionary again later.
I’ve created Spotlight metadata importer based on your code. Few issues:
• I’ve changed code to use autoreleased objects. You shoud use init/new/copy naming scheme for methods that return retained objects.
• It didn’t handle corrupted files gracefully. I’ve had to add bounds checks everywhere (probably still isn’t 100% correct).
• GPL v3 is very limiting for such software. Consider LGPL v2 or BSD license.