Skip to content

Instantly share code, notes, and snippets.

@blakesmith
Created June 8, 2011 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blakesmith/1015260 to your computer and use it in GitHub Desktop.
Save blakesmith/1015260 to your computer and use it in GitHub Desktop.
Bencoding implementation
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