Jump to content

Decode Bencode Function - Help Please!


Recommended Posts

I've been working on a huge project. Its a torrent downloader. I can't show the source or anything, sorry guies, that would be frowned upon by the Autoit forum moderators. I won't post a link either but it will be posted on google code in the near future so you can always search for it. I believe that any euthastic torrent downloader will absolutely love it. I would like to have a function to decode bencode torrent files. I've done the research. I need help writing this function. I thank you all in advance and really appreciate any help I recieve from these forums.

Features to implement once I can decode bencoded files:

(1) Generate magnet links from torrent files.

(2) List files inside torrent files.

(3) Conviently parse tracker response data for checking torrent trackers for torrent information before adding them to the generated magnet link and passing it to the client which actually downloads the torrent.

Spec - Wiki Theory Bittorrent Spec - Bencode - At the bottom of this page there are links to implementations in other languages.

Info - Wikipedia - Bencode

Bencode Editor - https://sites.google.com/site/ultimasites/bencode-editor - This is allegedly written in Autoit. Though I cannot find the source.

I completely rewrote the functions as one function. Its works well but is not exactly what I need. now that I can extract the information I need to associate each type appropiately.

For Example:

Strings => Integers

Lists => Strings

Dictionaries => Strings

Seeds => 1

Peers => 5

Tracker List => Tracker|Tracker|Tracker

This is complicated because lists can be in lists in dictionaries inside of dictionaries or other lists.

#include <array.au3>

$Timer = TimerInit()
Example(@ScriptDir & 'ubuntu-12.04-desktop-i386.iso.torrent')
ConsoleWrite(@CRLF & @CRLF & "Time: " & Round(TimerDiff($Timer)/1000, 1) & " second(s)" & @CRLF)

Func Example($sFilePath)
   Local $Bencode = FileRead($sFilePath)
   Local $aData = _Decode_Bencode($Bencode)
   _ArrayDisplay($aData)
EndFunc

Func _Decode_Bencode($sBencoded_Data)
   Local $iIndex = 0, $sDecoded_Data, $iEndIndex, $iDecoded_Integer, $iDecoded_Dim_0 = 0, $iDecoded_Dim_1 = 0, $iDecoded_Indent = 0
   Local $aDecoded_Array[20][20]
   If Not IsString($sBencoded_Data) Then
      Return SetError(1, 0, 0)
   EndIf
   Local $aBencoded_Data = StringSplit($sBencoded_Data, '', 2)
   While $iIndex <> UBound($aBencoded_Data, 1) - 1
      Switch $aBencoded_Data[$iIndex]
         Case "e"
            $iIndex += 1
            $iDecoded_Dim_0 += 1
            If $iDecoded_Indent <> 0 Then $iDecoded_Indent -= 1
            $iDecoded_Dim_1 = $iDecoded_Indent
            ContinueLoop
         Case "l"
            $iIndex += 1
            $iDecoded_Dim_1 = $iDecoded_Indent
            $iDecoded_Dim_0 += 1
            $iDecoded_Indent += 1
            ContinueLoop
         Case "d"
            $iIndex += 1
            $iDecoded_Dim_1 = $iDecoded_Indent
            $iDecoded_Dim_0 += 1
            $iDecoded_Indent += 1
            ContinueLoop
         Case "i"
            $iEndIndex = _ArraySearch($aBencoded_Data, "e", $iIndex, 0, 1)
            $sDecoded_Data = ""
            For $i = $iIndex + 1 To $iEndIndex - 1 Step 1
               $sDecoded_Data &= $aBencoded_Data[$i]
               $aBencoded_Data[$i] = ""
            Next
            $aDecoded_Array[$iDecoded_Dim_0][$iDecoded_Dim_1] = $sDecoded_Data
            $iIndex = $iEndIndex - 1
            $iDecoded_Dim_1 += 1
         Case 0 To 9
            $iDecoded_Integer = ""
            $iEndIndex = _ArraySearch($aBencoded_Data, ":", $iIndex)
            For $i = $iIndex To $iEndIndex - 1 Step 1
               $iDecoded_Integer &= $aBencoded_Data[$i]
               $aBencoded_Data[$i] = ""
            Next
            $sDecoded_Data = ""
            For $i = $iEndIndex + 1 To $iEndIndex + $iDecoded_Integer Step 1
               $sDecoded_Data &= $aBencoded_Data[$i]
               $aBencoded_Data[$i] = ""
            Next
            $aDecoded_Array[$iDecoded_Dim_0][$iDecoded_Dim_1] = $sDecoded_Data
            $iIndex = $iEndIndex + $iDecoded_Integer
            $iDecoded_Dim_1 += 1
      EndSwitch
      $iIndex += 1
   WEnd
   Return $aDecoded_Array
EndFunc

*Edited:

Original vbscript - http://demon.tw/my-work/vbs-bencode.html

Bencoded Torrent File: ubuntu-12.04-desktop-i386.iso.torrent

Thanks in advance!

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Unless you are actively encouraging piracy and illegal activity, I see no reason why this should be frowned upon.

Torrents are a fantastic way to distribute large files. Freeware projects that create large databases, or OS' like linux wouldn't be able to pay for hosting to support large http downloads, so wouldn't exist without p2p distribution.

Link to comment
Share on other sites

Unless you are actively encouraging piracy and illegal activity, I see no reason why this should be frowned upon.

Torrents are a fantastic way to distribute large files. Freeware projects that create large databases, or OS' like linux wouldn't be able to pay for hosting to support large http downloads, so wouldn't exist without p2p distribution.

I had posted the code before where it search the piratebay exclusively, Topic labeled TPB Torrent Downloader was deleted. If a mod happens to see this post please advice if I can post the code or not.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

You casees with "or", "and" are most certainly wrong.

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

They were all originally "And" but I replaced most of them with "Or". Which would be correct? I thought it might be better to use a < or > operators depending on whats happening in that function but I'm unsure.

Ex. Case $a >= 0 And <= 9

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

You cannot ask for a range with And. You have to specify the variable for each expression: Case $a >= 0 And $a <= 9

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

Your case statement needs to be rewritten like the code below.

Case $c = "0" Or $c = "$1" Or $c = "2" Or $c = "3" Or $c = "4" Or $c = "5" Or $c = "6" Or $c = "7" Or $c = "8" Or $c = "9"

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Thanks, I'll update the script above. @BrewManNH I assume the reason for coding it that way be because of the variable type correct?

You might be better off with a Switch statement in that section then you could just do it this way.

Switch $c
     Case "l"
     Case "d"
     Case "i"
     Case 0 To 9
EndSwitch

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

As the _Decode_String and Integer functions are working properly the key to fix this is:

Lists

Lists are encoded as follows: l<bencoded values="">e

The initial l and trailing e are beginning and ending delimiters. Lists may contain any bencoded type, including integers, strings, dictionaries, and even lists within other lists. Example: l4:spam4:eggse represents the list of two strings: [ "spam", "eggs" ]

Dictionaries

Dictionaries are encoded as follows: d<bencoded string=""><bencoded element="">e

The initial d and trailing e are the beginning and ending delimiters. Note that the keys must be bencoded strings. The values may be any bencoded type, including integers, strings, lists, and other dictionaries. Keys must be strings and appear in sorted order (sorted as raw strings, not alphanumerics). The strings should be compared using a binary comparison, not a culture-specific "natural" comparison. Example: d3:cow3:moo4:spam4:eggse represents the dictionary { "cow" => "moo", "spam" => "eggs" } Example: d4:spaml1:a1:bee' represents the dictionary { "spam" => [ "a", "b" ] } Example: d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee represents { "publisher" => "bob", "publisher-webpage" => "www.example.com", "publisher.location" => "home" }

I can not figure out how to fix these two iterative functions.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Im just thinking, if every "dictionary" is like that why not just make something that finds a number, removes the colon and reads the string until the next number and repeats.

d3:cow3:moo4:spam4:eggse

remove d

-

skip to next number

skip past number and :

read until next number

Save that string somewhere

-

repeat above until no more numbers

remove e at the end

[font="helvetica, arial, sans-serif"]Hobby graphics artist, using gimp.Automating pc stuff, using AutoIt.Listening to music, using Grooveshark.[/font]Scripts:[spoiler]Simple ScreenshotSaves you alot of trouble when taking a screenshot!Don't remember what happened with this, but aperantly the exe is all i got.If you don't want to run it, simply don't._IsRun UDFIt figures out if the script has ben ran before based on the info in a ini file.If you don't want to use exactly what i wrote, you can use it as inspiration.[/spoiler]

Link to comment
Share on other sites

Im just thinking, if every "dictionary" is like that why not just make something that finds a number, removes the colon and reads the string until the next number and repeats.

d3:cow3:moo4:spam4:eggse

remove d

-

skip to next number

skip past number and :

read until next number

Save that string somewhere

-

repeat above until no more numbers

remove e at the end

I understand your logic. I would like the Bdecode function to be able to decode any Bencode according to the spec.

d58:http://thisisaurlwithanamountofcharactersandthenumber8plus3:moo4:spam4:eggse

This would break the function. I thought to use RegEx but I don't know how to write it.

The way the _Decode_String() function is wriiten:

The String function would only be called if the starting character is a number 0 To 9.

Find the first colon after the starting character.

Extract the integer between the said number and the colon. The integer represents the amount of characters in a string.

Use StringMid to extract the string from the colon to the number of characters specified by the extracted integer.

For example: d5:fifthe

The Decode_Dict(String) function would call _Decode_String(String, StartingCharacter)

If 'd' is the place value of the starting character then the integer to be extracted is between 1 and 3(Colon)

5 is the amount of character in the string or content after the colon.

so we can then use stringmid to extract exactly that string.

We then return an array whose's first index is the decoded string 'fifth' and the second should be the position of 'e' an integer.

The Decode_Dict() function would then return because the starting character is an 'e'

That's the best I can explain it. Thanks for your suggestion but I'd really like to just fix the functions I have now then I could go back and optimize the code make changes, etc.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

So the number represent the ammount of letters that are gonna follow ?

(Sorry if you said already, but its hard to pay attention to everything)

I would put the string in a variable, and remove pices of the variable and saving the pices while you remove them.

This would make for easy coding i would belive.

Remind me to give it a go if i have time tomorrow!

[font="helvetica, arial, sans-serif"]Hobby graphics artist, using gimp.Automating pc stuff, using AutoIt.Listening to music, using Grooveshark.[/font]Scripts:[spoiler]Simple ScreenshotSaves you alot of trouble when taking a screenshot!Don't remember what happened with this, but aperantly the exe is all i got.If you don't want to run it, simply don't._IsRun UDFIt figures out if the script has ben ran before based on the info in a ini file.If you don't want to use exactly what i wrote, you can use it as inspiration.[/spoiler]

Link to comment
Share on other sites

I know that this shouldn't be as complicated as is to me but I've made progress I can actually can get some output. ;)

Please do and please run the code, I just updated it and the problems with it are very apparent than before. Thanks for any help.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

How can I make an array effectively without creating an array inside an array.

$aArray[1][0] = "List"

$aArray[1][1] = "Delimited-Strings"

$aArray[2][0] = "Spam"

$aArray[2][1] = "Eggs"

$aArray[3][0] = "Dictionary"

$aArray[3][1] = "Delimited-Keys"

Spoiler

censored.jpg

 

Link to comment
Share on other sites

I would like to create an array similiar to this:

Posted Image

$aArray[0][0] = announce

$aArray[0][1] = http://torrent.ubuntu.com:6969/announce

$aArray[1][0] = announce-list

$aArray[1][1] = http://torrent.ubuntu.com:6969/announce<--delimiter-->http://ipv6.torrent.ubuntu.com:6969/announce

$aArray[2][0] = comment

$aArray[2][1] = Ubuntu CD releases.ubuntu.com

$aArray[3][0] = creation date

$aArray[3][1] = 1335433885

$aArray[4][0] = length

$aArray[4][1] = 735358976

and so on.

Dictionary => Key Name would be [n][0] and value [n][1]

List => StringName would be [n][0] and value [n][1] if value is a list then delimit the strings and/or integers

This way I will always have a two dimensional array.

If I wanted the announce list I could just _ArraySearch for announce-list and StringSplit the value.

I can not determine how to manipulate the code to work as described.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

I can't see what the problem is.

Im sorry if i understand, but my ability to understand what you have written just isn't there.

You want multiple arrays without having an array in an array?

Why not give the array different names... ?

Sorry, but im lost.

[font="helvetica, arial, sans-serif"]Hobby graphics artist, using gimp.Automating pc stuff, using AutoIt.Listening to music, using Grooveshark.[/font]Scripts:[spoiler]Simple ScreenshotSaves you alot of trouble when taking a screenshot!Don't remember what happened with this, but aperantly the exe is all i got.If you don't want to run it, simply don't._IsRun UDFIt figures out if the script has ben ran before based on the info in a ini file.If you don't want to use exactly what i wrote, you can use it as inspiration.[/spoiler]

Link to comment
Share on other sites

I only want one two dimensional array containing the decoded data as described above the problem is how to do that when there are sometimes lists in lists in dictionaries in dictionaries or vice versa when decoding the bencode.

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...