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