def initialize(metainfo, out=nil, validity_assumption=nil)
info = metainfo.info
created = false
out ||= info.name
case out
when File
raise ArgumentError, "'out' cannot be a File for a multi-file .torrent" if info.multiple?
fstream = out
when Dir
raise ArgumentError, "'out' cannot be a Dir for a single-file .torrent" if info.single?
fstream = out
when String
if info.single?
rt_debug "output file is #{out}"
begin
fstream = File.open(out, "rb+")
rescue Errno::ENOENT
created = true
fstream = File.open(out, "wb+")
end
else
rt_debug "output directory is #{out}"
unless File.exists? out
Dir.mkdir(out)
created = true
end
fstream = Dir.open(out)
end
else
raise ArgumentError, "'out' should be a File, Dir or String object, is #{out.class}"
end
@ro = false
@size = info.total_length
if info.single?
@files = [[fstream, Mutex.new, info.length]]
else
@files = info.files.map do |finfo|
path = File.join(finfo.path[0, finfo.path.length - 1].inject(fstream.path) do |path, el|
dir = File.join(path, el)
unless File.exist? dir
rt_debug "making directory #{dir}"
Dir.mkdir dir
end
dir
end, finfo.path[finfo.path.length - 1])
rt_debug "opening #{path}..."
[open_file(path), Mutex.new, finfo.length]
end
end
i = 0
@pieces = info.pieces.unpack("a20" * (info.pieces.length / 20)).map do |hash|
start = (info.piece_length * i)
len = [info.piece_length, @size - start].min
p = Piece.new(i, hash, start, len, @files, (created ? false : validity_assumption))
p.on_event(self, :complete) { send_event(:complete) if complete? }
yield p if block_given?
(i += 1) && p
end
reopen_ro if complete?
end