Created
June 8, 2011 20:04
-
-
Save blakesmith/1015260 to your computer and use it in GitHub Desktop.
Bencoding implementation
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
require 'stringio' | |
module EM::Bittorrent | |
module Benc | |
def self.decode(input) | |
Stream.new(input).decode | |
end | |
class Stream | |
def initialize(input) | |
if input.is_a?(String) | |
@io = ::StringIO.new(input) | |
elsif input.is_a?(StringIO) | |
@io = input | |
elsif input.is_a?(File) | |
@io = input | |
else | |
raise ArgumentError.new "You must supply either a String or an IO object as input" | |
end | |
end | |
def decode | |
begin | |
@c = @io.getc | |
if @c == ?i | |
decode_int | |
elsif @c == ?l | |
decode_array | |
elsif @c == ?d | |
decode_hash | |
elsif @c =~ /[0-9]/ | |
decode_string | |
else # 'e' - end of element | |
nil | |
end | |
rescue TypeError | |
puts "Died at character #{@c}, position #{@io.pos}" | |
raise | |
end | |
end | |
private | |
def decode_string | |
::String.new.tap do |str| | |
len = ::String.new | |
len << @c | |
until ((@c = @io.getc) == ?:) | |
len << @c | |
end | |
str << @io.read(len.to_i) | |
end | |
end | |
def decode_int | |
::String.new.tap do |str| | |
until ((@c = @io.getc) == ?e) | |
str << @c | |
end | |
end.to_i | |
end | |
def decode_array | |
::Array.new.tap do |array| | |
while (value = decode) | |
array << value | |
end | |
end | |
end | |
def decode_hash | |
::Hash.new.tap do |hash| | |
while (key = decode) | |
value = decode | |
hash[key] = value | |
end | |
end | |
end | |
end | |
module Symbol | |
def to_benc | |
self.to_s.to_benc | |
end | |
end | |
module String | |
def to_benc | |
self.class.new.tap do |s| | |
s << self.length.to_s | |
s << ?: | |
s << self | |
end | |
end | |
end | |
module Integer | |
def to_benc | |
::String.new.tap do |s| | |
s << ?i | |
s << self.to_s | |
s << ?e | |
end | |
end | |
end | |
module Array | |
def to_benc | |
::String.new.tap do |s| | |
s << ?l | |
self.each do |item| | |
s << item.to_benc | |
end | |
s << ?e | |
end | |
end | |
end | |
module Hash | |
def to_benc | |
::String.new.tap do |s| | |
s << ?d | |
self.each do |k, v| | |
s << k.to_benc | |
s << v.to_benc | |
end | |
s << ?e | |
end | |
end | |
end | |
end | |
end | |
Symbol.send(:include, EM::Bittorrent::Benc::Symbol) | |
String.send(:include, EM::Bittorrent::Benc::String) | |
Integer.send(:include, EM::Bittorrent::Benc::Integer) | |
Array.send(:include, EM::Bittorrent::Benc::Array) | |
Hash.send(:include, EM::Bittorrent::Benc::Hash) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment