require 'yaml'

module BinaryIO

# Failed to read binary data.
class BinaryReadError < IOError
end

# Based on BinaryReader class by Michael Neumann
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/23048
class BinaryReader

  # Config file containing info about the types of data to be read.
  CONFIG = 'BinaryIO.yaml'

	File.open("#{File.dirname(__FILE__)}/#{CONFIG}") do |file|
		YAML::load(file).each_pair do |meth, data|
			eval %{
				def read_#{meth}(n = 1)
					_read(n, #{data[:size]}, '#{data[:format]}')
				end
			}
		end
	end

  # handle:: stream to read from.
	def initialize(handle)
		@handle = handle
	end

  # n:: Number of data items to read.
  # size:: Size of each data item in bytes.
  # format:: Format string for each data item (See String#unpack).
	protected
	def _read(n, size, format)
		bytes = n * size

    begin
      str = @handle.read(bytes)
    rescue IOError => exception
      raise BinaryReadError, exception.message
    end

    unless str.length == bytes
      raise BinaryReadError, "Read #{str.size} bytes when expecting #{bytes} bytes"
    end
    
		val = str.unpack(format * n)

		if n == 1
			val.first
		else
			val
		end
	end
end

end