Skip to content

Instantly share code, notes, and snippets.

@TheOnlyArtz
Created January 5, 2020 19:16
Show Gist options
  • Save TheOnlyArtz/aa87839d6977fe722c40f797ba6e913f to your computer and use it in GitHub Desktop.
Save TheOnlyArtz/aa87839d6977fe722c40f797ba6e913f to your computer and use it in GitHub Desktop.
# 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