rubyzip/lib/zip/input_stream.rb

146 lines
4.2 KiB
Ruby
Raw Normal View History

module Zip
# ZipInputStream is the basic class for reading zip entries in a
# zip file. It is possible to create a ZipInputStream object directly,
# passing the zip file name to the constructor, but more often than not
# the ZipInputStream will be obtained from a ZipFile (perhaps using the
# ZipFileSystem interface) object for a particular entry in the zip
# archive.
#
# A ZipInputStream inherits IOExtras::AbstractInputStream in order
# to provide an IO-like interface for reading from a single zip
# entry. Beyond methods for mimicking an IO-object it contains
# the method get_next_entry for iterating through the entries of
# an archive. get_next_entry returns a ZipEntry object that describes
# the zip entry the ZipInputStream is currently reading from.
#
# Example that creates a zip archive with ZipOutputStream and reads it
# back again with a ZipInputStream.
#
# require 'zip/zip'
#
# Zip::ZipOutputStream::open("my.zip") {
# |io|
#
# io.put_next_entry("first_entry.txt")
# io.write "Hello world!"
#
# io.put_next_entry("adir/first_entry.txt")
# io.write "Hello again!"
# }
#
#
# Zip::ZipInputStream::open("my.zip") {
# |io|
#
# while (entry = io.get_next_entry)
# puts "Contents of #{entry.name}: '#{io.read}'"
# end
# }
#
# java.util.zip.ZipInputStream is the original inspiration for this
# class.
class InputStream
2013-06-03 02:33:03 +08:00
include ::Zip::IOExtras::AbstractInputStream
# Opens the indicated zip file. An exception is thrown
# if the specified offset in the specified filename is
# not a local zip entry header.
2012-01-26 21:50:25 +08:00
def initialize(filename, offset = 0, io = nil)
super()
2012-01-26 21:50:25 +08:00
if (io.nil?)
2012-02-01 03:46:42 +08:00
@archiveIO = ::File.open(filename, "rb")
2012-01-26 21:50:25 +08:00
@archiveIO.seek(offset, IO::SEEK_SET)
else
@archiveIO = io
end
@decompressor = NullDecompressor.instance
@currentEntry = nil
end
def close
@archiveIO.close
end
# Same as #initialize but if a block is passed the opened
# stream is passed to the block and closed when the block
# returns.
def InputStream.open(filename)
return new(filename) unless block_given?
zio = new(filename)
yield zio
ensure
zio.close if zio
end
def InputStream.open_buffer(io)
2012-01-26 21:50:25 +08:00
return new('',0,io) unless block_given?
zio = new('',0,io)
yield zio
ensure
zio.close if zio
end
# Returns a ZipEntry object. It is necessary to call this
# method on a newly created ZipInputStream before reading from
# the first entry in the archive. Returns nil when there are
# no more entries.
def get_next_entry
@archiveIO.seek(@currentEntry.next_header_offset, IO::SEEK_SET) if @currentEntry
open_entry
end
# Rewinds the stream to the beginning of the current entry
def rewind
return if @currentEntry.nil?
@lineno = 0
@pos = 0
2013-06-03 02:33:03 +08:00
@archiveIO.seek(@currentEntry.local_header_offset,
IO::SEEK_SET)
open_entry
end
# Modeled after IO.sysread
def sysread(numberOfBytes = nil, buf = nil)
@decompressor.sysread(numberOfBytes, buf)
end
def eof
2013-06-03 02:33:03 +08:00
@output_buffer.empty? && @decompressor.eof
end
alias :eof? :eof
protected
def open_entry
@currentEntry = Entry.read_local_entry(@archiveIO)
if @currentEntry.nil?
@decompressor = NullDecompressor.instance
elsif @currentEntry.compression_method == Entry::STORED
@decompressor = PassThruDecompressor.new(@archiveIO, @currentEntry.size)
elsif @currentEntry.compression_method == Entry::DEFLATED
@decompressor = Inflater.new(@archiveIO)
else
raise ZipCompressionMethodError,
"Unsupported compression method #{@currentEntry.compression_method}"
end
flush
return @currentEntry
end
def produce_input
@decompressor.produce_input
end
def input_finished?
@decompressor.input_finished?
end
end
end
# Copyright (C) 2002, 2003 Thomas Sondergaard
# rubyzip is free software; you can redistribute it and/or
# modify it under the terms of the ruby license.