Introducing Torrent Utility, an Apollo application

Recently, I’ve been looking into the technology and implementation behind BitTorrent, a peer-to-peer technology that has risen to extreme popularity in the last few years. Adobe’s new cross-platform runtime codenamed Apollo just came out, and I needed a project to get my feet wet. I decided to built a simple application that allows you to read the contents of a .torrent file or even create a new torrents from files directly on your hard drive to upload to your favorite tracker. It’s a fun little project that has already come in handy for a couple people.

Screenshot of Torrent Utility

Let’s start by taking a look at some of the implementation details related to the BitTorrent specification. Particularly of note is the class Bencoder. BitTorrent uses a special encoding system that you might find similar to JSON. It’s a very light-weight way to encode data, and it only a supports a few types: numbers, strings, dictionaries (objects), and lists (arrays). Consider the following Bencoded object for an idea of how it looks:

d4:name4:Josh9:highscorei12100ee

In ActionScript, you would declare the same object like this:

{name: "Josh", highscore: 12100}

The Bencoder class handles encoding and decoding ActionScript objects with this format.

When reading .torrent files, the readTorrentData function is where the magic happens. An interesting thing about this file format is that it isn’t all plain-text, as you’d expect it to be with the Bencode specification I described above. Torrent files have a section of binary data that is hashed with the SHA-1 algorithm, and this is stored in binary. If you try to read this section with ByteArray.readUTFBytes(), the function may stop early and you won’t get the correct data. So, this function reads the first string-based part of the file, then the binary section which is encoded like a string with the length at the beginning, then the final string-based portion.

private function readTorrentData(torrentStream:FileStream):void
{
	//get the first part of the file
	var fileData:String = this.readDataBeforeHashes(torrentStream);

	//read the hash pieces
	var piecesLength:int = this.readPiecesLength(torrentStream);
	var hashes:ByteArray = new ByteArray();
	torrentStream.readBytes(hashes, 0, int(piecesLength));

	//add the readable hash length to the file
	fileData += (piecesLength * 2) + ":";

	//add the readable hex hashes to the file
	fileData += ByteUtil.byteArrayToHexString(hashes);

	//add the end of the file
	fileData += torrentStream.readUTFBytes(torrentStream.bytesAvailable);

	torrentStream.close();

	this.parseTorrentData(fileData);
}

You’ll notice a call to the byteArrayToHexString function in my ByteUtil class. This function converts the raw bytes into human-readable hex strings. The class also includes a corresponding function that will convert a hex string back to ByteArray.

Grab the AIR installation file for Torrent Utility, and give it a try. If you’d like a closer look, download the MIT-licensed source code as well. Please note that you will need the latest build of Adobe’s corelib, version 0.90, to build the source. The version includes the enhancements to the SHA1 class that I wrote specifically when I needed them for this application.

You will, of course, need the alpha release of the Apollo runtime, which you can download on Adobe Labs. Please remember, Apollo is pre-release developer software that will contain bugs, may erase your hard drive, and it might even rape your dog and call your grandma offensive names. In other words, use with caution and don’t expect it to be polished.

About Josh Tynjala

Josh Tynjala is a frontend developer, open source contributor, bowler hat enthusiast, and karaoke addict. You might be familiar with his project, Feathers UI, an open source user interface library for Starling Framework that is included in the Adobe Gaming SDK.

Discussion

  1. Ian Chia

    Very nice work. Needs a minor error check at the start – I created a new torrent using the utility by accident, but didn’t populate it. Then opened the same torrent file and it hangs the Torrent Utility app – have to kill the process. Worked very nicely on “normal” torrents though. (-;

    – Ian

  2. Juraj Varady

    I have downloaded right file,not source ,(AIR file),but there is no *.AIR file there.
    Check “AIR file” link and archive it downloads pls. Thx

  3. Josh Tynjala

    Okay, I found the problem. I had heard that downloading AIR files doesn’t always work. The problem is with Internet Explorer. I use Firefox on both PC and Mac, so I never noticed the issue.

    The link truly does point to an AIR file. You can see that when you put your mouse over it, even in IE. For some strange reason, IE thinks it should actually be a ZIP file when you try to download the file. Just change the ZIP extension to AIR and it will work fine.

    I’ll see if I can find the fix Adobe recommends.

  4. Pingback: TorrentUtility AIR application now runs on beta » Zeus Labs

  5. Humbert HARDY

    I have found a little error in ByteUtil.as, in the byteArrayToHexString function.You have forgotten to initialize the data.position before the “while” instruction. It is usefull if you wanna use this function in other applications.

    public static function byteArrayToHexString(data:ByteArray):String{
    var oldPosition:int = data.position;
    var joinedBytes:String = “”;
    […]

    Must be replace by:

    public static function byteArrayToHexString(data:ByteArray):String
    {
    var oldPosition:int = data.position;
    data.position=0;
    var joinedBytes:String = “”;
    […]
    Thanks for this application!!

  6. Steve

    Not good enough ! I want to read the whole contents of a torrent file in human readable maner ! Why ? Some torrent file caries much info abaut files when is more than one file included ! I can view this with TCM Lister plugin but not in human readable way ! So what to use to not encode edit and losse much time to do all by the hand ?