lib/bencoding/parser.rb in simonmenke-bencoding-0.0.2 vs lib/bencoding/parser.rb in simonmenke-bencoding-0.0.3
- old
+ new
@@ -1,43 +1,68 @@
module Bencoding
- class ParseError < Exception ; end
+ class ParseError < Exception ; end
+ class InvalidInput < Exception ; end
module Parser
DICTIONARY_TOKEN = 100 # d # :nodoc:
LIST_TOKEN = 108 # l # :nodoc:
INTEGER_TOKEN = 105 # i # :nodoc:
TERMINATOR_TOKEN = 101 # e # :nodoc:
SEPERATOR_TOKEN = 58 # : # :nodoc:
- ZERO_TOKEN = 48 # : # :nodoc:
- NINE_TOKEN = 57 # : # :nodoc:
+ ZERO_TOKEN = 48 # 0 # :nodoc:
+ NINE_TOKEN = 57 # 9 # :nodoc:
+ MINUS_TOKEN = 45 # - # :nodoc:
def load(io)
- io = StringIO.new(io) if io.is_a? String
- parse_anytype(io)
+ any_io(io) do |io|
+ parse_anytype(io)
+ end
end
+ def any_io(io)
+ close_io = false
+ if io.is_a? String
+ if io =~ %r{^(http(s?)|file)://}
+ io = open(io)
+ close_io = true
+ elsif File.exist?(io)
+ io = File.open(io)
+ close_io = true
+ else
+ io = StringIO.new(io)
+ end
+ end
+
+ raise InvalidInput unless io.respond_to?(:getc)
+ raise InvalidInput unless io.respond_to?(:read)
+ raise InvalidInput unless io.respond_to?(:close) or not close_io
+
+ return_value = yield(io)
+
+ io.close if close_io
+ return return_value
+ end
+
def parse_anytype(io, typechar=nil) # :nodoc:
typechar ||= io.getc
case typechar
when DICTIONARY_TOKEN then parse_dictionary(io)
when LIST_TOKEN then parse_list(io)
when INTEGER_TOKEN then parse_integer(io)
when (ZERO_TOKEN..NINE_TOKEN)
- io.ungetc typechar
- parse_string(io)
+ parse_string(io, typechar)
else
raise ParseError
end
end
def parse_dictionary(io) # :nodoc:
dictionary = ::Hash.new
until (c = io.getc) == TERMINATOR_TOKEN
raise ParseError if c.nil?
- io.ungetc c
- key = parse_string(io)
+ key = parse_string(io, c)
val = parse_anytype(io)
dictionary[key] = val
end
dictionary
end
@@ -50,21 +75,26 @@
list << val
end
list
end
- def parse_integer(io, terminator=TERMINATOR_TOKEN) # :nodoc:
+ def parse_integer(io, terminator=TERMINATOR_TOKEN, first_char=nil) # :nodoc:
integer_string = ""
+ integer_string << first_char unless first_char.nil?
until (c = io.getc) == terminator
- raise ParseError if c.nil?
- integer_string << c.chr
+ raise ParseError if c.nil?
+ raise ParseError unless (ZERO_TOKEN..NINE_TOKEN).member?(c) or MINUS_TOKEN == c
+ integer_string << c
end
integer_string.to_i
end
- def parse_string(io) # :nodoc:
- length = parse_integer(io, SEPERATOR_TOKEN)
- io.read(length)
+ def parse_string(io, first_char) # :nodoc:
+ length = parse_integer(io, SEPERATOR_TOKEN, first_char)
+ raise ParseError if length < 0
+ string = io.read(length)
+ raise ParseError if length != string.length
+ string
end
extend self
end