Sign in to follow this  
Followers 0
Decipher

Decode Bencode Function - Help Please!

23 posts in this topic

#1 ·  Posted (edited)

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

 

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

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

 

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

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

 

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

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

Edited by Decipher

Spoiler

censored.jpg

 

Share this post


Link to post
Share on other sites

There is no typecasting in AutoIt. An integer is a string is a double is a long.

1 person likes this

Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

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

 

Share this post


Link to post
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]

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

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

 

Share this post


Link to post
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]

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

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

 

Share this post


Link to post
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

 

Share this post


Link to post
Share on other sites

#include <Array.au3>

Local $aArray[4][2] = [[0, 1], [2, 3], ['4', '5']]
$aArray[3][0] = 6
$aArray[3][1] = '7'

_ArrayDisplay($aArray)

?

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

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

 

Share this post


Link to post
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]

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

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

 

Share this post


Link to post
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
Sign in to follow this  
Followers 0

  • Similar Content

    • mati
      By mati
      Hi,
      I wonder if
      AutoIt3Wrapper_run_debug_mode = Y can include run information about functions which are called within the main code. So far I noticed in the console that the function itself is called but no specific run information from  inside the function is provided. Is there a chance to show the entire debug log including functions in the console?
      I furthermore noticed a stop of information when a loop is entered. What could be the reason for that?
       
      Thanks for help.
    • TrashBoat
      By TrashBoat
      Is this possible:
      Executing a function from an include, but taking the function name from a gui input and then executing that function using the include:
      #include <Something.au3> ;input reads "Tree" $functionName = GuiCtrlRead($input1) $functionName(1) And the include is gonna have
      Func Tree($x) If $x = 1 Then $this = "text" MsgBox(0,$this,"whatever") EndFunc is it possible?
    • hcI
      By hcI
      Hello, i'm making a little script that lets users enter a question and if the script can't answer to, it ask what would be the answer (a bit like siri on IPhones). And I try to display the "supposed array" I still have an error.. I searched on Google and got nothing looked in the help file too.. I'm here to know if someone have a solution to my error please.
      Here is where $a and $b should become arrays :
      Dim $dossier = @AppDataDir & "\Siri2" Dim $chemin = $dossier & "\data.ini" Global $a = _InfoRead($chemin, 0) Global $b = _InfoRead($chemin, 1) with this function :
      Func _InfoRead($path, $mode = 0) If DirGetSize($dossier) = -1 Then Return SetError(-4) If Not FileExists($chemin) Then Return SetError(-5) Local $readed = IniReadSection($path, "data") If @error Then Return SetError(-3) $size = $readed[0][0] Local $return[$size] For $i = 1 To $size Step 1 $return[$i - 1] = $readed[$i][$mode] Next Return $return EndFunc and the thing that i don't understand is that, after _InfoRead return affected to $a, I can't use _ArrayDisplay because of  error 1 "$aArray is not an array" (and same fpr the variable $b)..
      Can please someone help me to understand why is it doing this ?

      -hcI
    • kawliga751
      By kawliga751
      I'm new to Auotit but I have built a simple script that "runs" a different "batch" file based on certain days of the workweek. The script works now, but I was wanting to eliminate the need for a manual date entry. For example "First Batch' needs to run every Tuesday thru Thursday however "Second Batch" needs to run only on Friday and "Third Batch" needs to run only on Monday. In addition the 1st batch file runs on Tuesday, say 06/06 (the "FW" section) but then needs to actually report (the F4 date) the next weekday so this Batch actually needs 2 dates verified. 
      What I'm trying to do is when the script is initiated it gets the date, verifies if and which weekday it is and in turn goes to and runs the appropriate "Batch' file.  
      I've found ways to verify weekdays but can't find anything to do all of the above.
      Any help is MUCH appreciated.
       
      ;P10
      ShellExecute("C:\Program Files (x86)\Ericom Software\PowerTerm Enterprise\Sessions\mir00p10.PTS")

      WinWait('(A) Soutwest P10 : PowerTerm Pro Enterprise Suite')
      WinActivate('(A) Soutwest P10 : PowerTerm Pro Enterprise Suite')
      Send('$Login)
      Sleep(3000)
      Send('{Enter}')
      Sleep(3000)
      Send($Password)
      Send('{Enter}')
      Sleep(3000)
      ; ****First Batch file run
      Send('Batch')
      Sleep(3000)
      Send('{Enter}')
      Send('FW')
      Send('{Enter}')
      Send('{DOWN}')
      Send($Date)
      Send('{Enter}')
      Send('{Enter}')
      Send($Date)
      Send('{F9}')
      Send('Y')
      Sleep(3000)
      Send('{Enter}')
      Send('{F4}')
      Send('Y')
      Sleep(3000)
      Send('{Enter}')
      Send($Date)
      Send('{Enter}')
      Send('0620')
      Send('{Enter}')
      SEND('{!}SW0410PM.FWR')
      Send('{Enter}')
      Sleep(3000)
      Send('Y')
      Send('{Enter}')
      Sleep(3000)
      Send('{F9}')
      Sleep(3000)
      ; ****Second Batch file run
      Send('Batch')
      Sleep(3000)
      Send('{Enter}')
      Send('FW')
      Send('{Enter}')
      Send('{DOWN}')
      Send($Date)
      Send('{Enter}')
      Send('{Enter}')
      Send($Date)
      Send('{F9}')
      Send('Y')
      Sleep(3000)
      Send('{Enter}')
      Send('{F4}')
      Send('Y')
      Sleep(3000)
      Send('{Enter}')
      Send($Date)
      Send('{Enter}')
      Send('0620')
      Send('{Enter}')
      SEND('{!}SO0411AM.FWR')
      Send('{Enter}')
      Sleep(3000)
      Send('Y')
      Send('{Enter}')
      Sleep(3000)
      Send('{F9}')
      Sleep(3000)
      ; ****Third Batch file run
      Send('Batch')
      Sleep(3000)
      Send('{Enter}')
      Send('FW')
      Send('{Enter}')
      Send('{DOWN}')
      Send($Date)
      Send('{Enter}')
      Send('{Enter}')
      Send($Date)
      Send('{F9}')
      Send('Y')
      Sleep(3000)
      Send('{Enter}')
      Send('{F4}')
      Send('Y')
      Sleep(3000)
      Send('{Enter}')
      Send($Date)
      Send('{Enter}')
      Send('0620')
      Send('{Enter}')
      SEND('{!}SW0411AM.LOA')
      Send('{Enter}')
      Sleep(3000)
      Send('Y')
      Send('{Enter}')
      Sleep(3000)
      Send('{F9}')
      Sleep(3000)
      Send('EXIT')
       
       
    • steveeye
      By steveeye
      Hi, can anybody explain "pure virtual function" and how to make use of them?