-
-
Save TheOnlyArtz/aa87839d6977fe722c40f797ba6e913f to your computer and use it in GitHub Desktop.
This file contains 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
# TODO: Write documentation for `Bencodecr` | |
module Bencodecr | |
VERSION = "0.1.0" | |
enum States | |
STATE_NULL, | |
STATE_INT, | |
STATE_STR_LEN, | |
STATE_STR_CONTENT, | |
STATE_LIST, | |
STATE_DICTIONARY | |
end | |
def self.load_torrent(path : String) : Slice(UInt8) | |
file = File.open(path, "r") | |
file.gets_to_end.to_slice | |
end | |
alias BenCodeObject = Hash(String, Hash(String, String | Array(String)) | Array(String) | String) | |
alias BenCodeArray = Array(String | Array(String) | Hash(String, String | Array(String))) | |
def self.parse(bytes : Slice(UInt8), idx : Int32) | |
length = bytes.size | |
index = idx | |
state = States::STATE_NULL | |
current : String = "" | |
current_object = BenCodeObject.new | |
# current_arr = Array(Int32 | String | Hash(String, String | Array(String)) | Array(String)).new | |
current_arr = BenCodeArray.new | |
current_string_length = 0 | |
while index < length | |
curr_char = bytes[index].chr | |
# p index, state | |
case state | |
when States::STATE_NULL | |
case curr_char | |
when 'i' | |
# p "STATE_INT" | |
state = States::STATE_INT | |
current = "" | |
next | |
when '0'..'9' | |
# p "STATE_STR_LEN" | |
state = States::STATE_STR_LEN | |
next | |
when 'l' | |
# p "STATE_LIST" | |
current_arr = BenCodeArray.new | |
state = States::STATE_LIST | |
when 'd' | |
current_object = BenCodeObject.new | |
state = States::STATE_DICTIONARY | |
else | |
return nil | |
end | |
index += 1 | |
when States::STATE_INT | |
case curr_char | |
when '-' # Them negative numbers should start with a minus shouldn't they? | |
current = "-" | |
when 'e' | |
# p "STATE_INT CURRENT", current | |
return {"o" => current, "index" => index + 1} | |
when '0'..'9' | |
current += curr_char | |
end # this closes the case curr_char of STATE_INT | |
index += 1 | |
when States::STATE_STR_LEN | |
case curr_char | |
when ':' | |
current_string_length = current.to_i | |
state = States::STATE_STR_CONTENT | |
current = "" | |
when '0'..'9' | |
current += curr_char | |
else | |
return nil | |
end | |
index += 1 | |
when States::STATE_STR_CONTENT | |
current += curr_char | |
# p "MY STATE IS STATE_STR_CONTENT YO YO => #{current}[#{current_string_length}]" | |
if ((current_string_length - 1) == 0) | |
return {"o" => current, "index" => index + 1} | |
end | |
current_string_length -= 1 | |
index += 1 | |
when States::STATE_DICTIONARY | |
if curr_char == 'e' | |
return {"o" => current_object, "index" => index + 1} | |
else | |
obj_key = self.parse(bytes, index) | |
if obj_key != nil | |
obj_val = self.parse(bytes, obj_key.not_nil!["index"].as(Int32)) | |
# p obj_val | |
if obj_val != nil | |
begin | |
current_object[obj_key.not_nil!["o"].as(String)] = obj_val.not_nil!["o"].as(String) | |
rescue | |
current_object[obj_key.not_nil!["o"].as(String)] = "asf" | |
end | |
index = obj_val.not_nil!["index"].as(Int32) | |
p index, length | |
break if index >= length | |
end | |
end | |
end | |
when States::STATE_LIST | |
if curr_char == 'e' | |
return {"o" => current_arr, "index" => index + 1} | |
else | |
obj = self.parse(bytes, index) | |
if obj != nil | |
# p obj.not_nil!["o"] | |
begin | |
a = obj.not_nil!["o"].as(String) | |
current_arr << a | |
rescue | |
current_arr << ["as"] | |
# Do not cast | |
end | |
index = obj.not_nil!["index"].as(Int32) | |
end | |
end | |
end | |
end | |
end | |
def self.decode(bytes : Slice(UInt8)) | |
object = self.parse(bytes, 0) | |
object.not_nil!["o"] | |
end | |
end | |
bytes = Bencodecr.load_torrent "src/ubuntu-19.10-desktop-amd64.iso.torrent" | |
s = Bencodecr.decode(bytes) | |
pp s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment