diff --git a/lib/zip.rb b/lib/zip.rb index fa382376..5261fd77 100644 --- a/lib/zip.rb +++ b/lib/zip.rb @@ -4,6 +4,7 @@ require 'fileutils' require 'stringio' require 'zlib' +require 'zip/constants' require 'zip/dos_time' require 'zip/ioextras' require 'rbconfig' @@ -21,6 +22,7 @@ require 'zip/null_input_stream' require 'zip/pass_thru_compressor' require 'zip/pass_thru_decompressor' +require 'zip/crypto/decrypted_io' require 'zip/crypto/encryption' require 'zip/crypto/null_encryption' require 'zip/crypto/traditional_encryption' @@ -28,7 +30,6 @@ require 'zip/deflater' require 'zip/streamable_stream' require 'zip/streamable_directory' -require 'zip/constants' require 'zip/errors' module Zip diff --git a/lib/zip/constants.rb b/lib/zip/constants.rb index 5eb5c1da..6feda25d 100644 --- a/lib/zip/constants.rb +++ b/lib/zip/constants.rb @@ -60,4 +60,56 @@ module Zip FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze, FSTYPE_ATHEOS => 'AtheOS'.freeze }.freeze + + COMPRESSION_METHOD_STORE = 0 + COMPRESSION_METHOD_SHRINK = 1 + COMPRESSION_METHOD_REDUCE_1 = 2 + COMPRESSION_METHOD_REDUCE_2 = 3 + COMPRESSION_METHOD_REDUCE_3 = 4 + COMPRESSION_METHOD_REDUCE_4 = 5 + COMPRESSION_METHOD_IMPLODE = 6 + # RESERVED = 7 + COMPRESSION_METHOD_DEFLATE = 8 + COMPRESSION_METHOD_DEFLATE_64 = 9 + COMPRESSION_METHOD_PKWARE_DCLI = 10 + # RESERVED = 11 + COMPRESSION_METHOD_BZIP2 = 12 + # RESERVED = 13 + COMPRESSION_METHOD_LZMA = 14 + # RESERVED = 15 + COMPRESSION_METHOD_IBM_CMPSC = 16 + # RESERVED = 17 + COMPRESSION_METHOD_IBM_TERSE = 18 + COMPRESSION_METHOD_IBM_LZ77 = 19 + COMPRESSION_METHOD_JPEG = 96 + COMPRESSION_METHOD_WAVPACK = 97 + COMPRESSION_METHOD_PPMD = 98 + COMPRESSION_METHOD_AES = 99 + + COMPRESSION_METHODS = { + COMPRESSION_METHOD_STORE => 'Store (no compression)', + COMPRESSION_METHOD_SHRINK => 'Shrink', + COMPRESSION_METHOD_REDUCE_1 => 'Reduce with compression factor 1', + COMPRESSION_METHOD_REDUCE_2 => 'Reduce with compression factor 2', + COMPRESSION_METHOD_REDUCE_3 => 'Reduce with compression factor 3', + COMPRESSION_METHOD_REDUCE_4 => 'Reduce with compression factor 4', + COMPRESSION_METHOD_IMPLODE => 'Implode', + # RESERVED = 7 + COMPRESSION_METHOD_DEFLATE => 'Deflate', + COMPRESSION_METHOD_DEFLATE_64 => 'Deflate64(tm)', + COMPRESSION_METHOD_PKWARE_DCLI => 'PKWARE Data Compression Library Imploding (old IBM TERSE)', + # RESERVED = 11 + COMPRESSION_METHOD_BZIP2 => 'BZIP2', + # RESERVED = 13 + COMPRESSION_METHOD_LZMA => 'LZMA', + # RESERVED = 15 + COMPRESSION_METHOD_IBM_CMPSC => 'IBM z/OS CMPSC Compression', + # RESERVED = 17 + COMPRESSION_METHOD_IBM_TERSE => 'IBM TERSE (new)', + COMPRESSION_METHOD_IBM_LZ77 => 'IBM LZ77 z Architecture (PFS)', + COMPRESSION_METHOD_JPEG => 'JPEG variant', + COMPRESSION_METHOD_WAVPACK => 'WavPack compressed data', + COMPRESSION_METHOD_PPMD => 'PPMd version I, Rev 1', + COMPRESSION_METHOD_AES => 'AES encryption', + }.freeze end diff --git a/lib/zip/crypto/decrypted_io.rb b/lib/zip/crypto/decrypted_io.rb new file mode 100644 index 00000000..ec9cab8b --- /dev/null +++ b/lib/zip/crypto/decrypted_io.rb @@ -0,0 +1,39 @@ +module Zip + class DecryptedIo #:nodoc:all + CHUNK_SIZE = 32_768 + + def initialize(io, decrypter) + @io = io + @decrypter = decrypter + end + + def read(length = nil, outbuf = '') + return ((length.nil? || length.zero?) ? "" : nil) if eof + + while length.nil? || (buffer.bytesize < length) + break if input_finished? + buffer << produce_input + end + + outbuf.replace(buffer.slice!(0...(length || output_buffer.bytesize))) + end + + private + + def eof + buffer.empty? && input_finished? + end + + def buffer + @buffer ||= ''.dup + end + + def input_finished? + @io.eof + end + + def produce_input + @decrypter.decrypt(@io.read(CHUNK_SIZE)) + end + end +end diff --git a/lib/zip/decompressor.rb b/lib/zip/decompressor.rb index 047ed5e7..2f89545c 100644 --- a/lib/zip/decompressor.rb +++ b/lib/zip/decompressor.rb @@ -1,9 +1,27 @@ module Zip class Decompressor #:nodoc:all CHUNK_SIZE = 32_768 - def initialize(input_stream) + + def self.decompressor_classes + @decompressor_classes ||= {} + end + + def self.register(compression_method, decompressor_class) + decompressor_classes[compression_method] = decompressor_class + end + + def self.find_by_compression_method(compression_method) + decompressor_classes[compression_method] + end + + attr_reader :input_stream + attr_reader :decompressed_size + + def initialize(input_stream, decompressed_size = nil) super() + @input_stream = input_stream + @decompressed_size = decompressed_size end end end diff --git a/lib/zip/entry.rb b/lib/zip/entry.rb index f6d5cb5e..f1963d8d 100644 --- a/lib/zip/entry.rb +++ b/lib/zip/entry.rb @@ -72,6 +72,14 @@ def initialize(*args) @extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.is_a?(::Zip::ExtraField) end + def encrypted? + gp_flags & 1 == 1 + end + + def incomplete? + gp_flags & 8 == 8 + end + def time if @extra['UniversalTime'] @extra['UniversalTime'].mtime diff --git a/lib/zip/errors.rb b/lib/zip/errors.rb index 364c6eee..0ff0e1e1 100644 --- a/lib/zip/errors.rb +++ b/lib/zip/errors.rb @@ -7,6 +7,7 @@ class EntryNameError < Error; end class EntrySizeError < Error; end class InternalError < Error; end class GPFBit3Error < Error; end + class DecompressionError < Error; end # Backwards compatibility with v1 (delete in v2) ZipError = Error diff --git a/lib/zip/file.rb b/lib/zip/file.rb index e0c62443..45017822 100644 --- a/lib/zip/file.rb +++ b/lib/zip/file.rb @@ -49,7 +49,7 @@ class File < CentralDirectory MAX_SEGMENT_SIZE = 3_221_225_472 MIN_SEGMENT_SIZE = 65_536 DATA_BUFFER_SIZE = 8192 - IO_METHODS = [:tell, :seek, :read, :close] + IO_METHODS = [:tell, :seek, :read, :eof, :close] DEFAULT_OPTIONS = { restore_ownership: false, diff --git a/lib/zip/inflater.rb b/lib/zip/inflater.rb index f1b26d45..4e217f6f 100644 --- a/lib/zip/inflater.rb +++ b/lib/zip/inflater.rb @@ -1,64 +1,50 @@ module Zip class Inflater < Decompressor #:nodoc:all - def initialize(input_stream, decrypter = NullDecrypter.new) - super(input_stream) - @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS) - @output_buffer = ''.dup - @has_returned_empty_string = false - @decrypter = decrypter - end + def initialize(*args) + super - def sysread(number_of_bytes = nil, buf = '') - readEverything = number_of_bytes.nil? - while readEverything || @output_buffer.bytesize < number_of_bytes - break if internal_input_finished? - @output_buffer << internal_produce_input(buf) - end - return value_when_finished if @output_buffer.bytesize == 0 && input_finished? - end_index = number_of_bytes.nil? ? @output_buffer.bytesize : number_of_bytes - @output_buffer.slice!(0...end_index) + @buffer = ''.dup + @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS) end - def produce_input - if @output_buffer.empty? - internal_produce_input - else - @output_buffer.slice!(0...(@output_buffer.length)) + def read(length = nil, outbuf = '') + return ((length.nil? || length.zero?) ? "" : nil) if eof + + while length.nil? || (@buffer.bytesize < length) + break if input_finished? + @buffer << produce_input end + + outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize))) end - # to be used with produce_input, not read (as read may still have more data cached) - # is data cached anywhere other than @outputBuffer? the comment above may be wrong - def input_finished? - @output_buffer.empty? && internal_input_finished? + def eof + @buffer.empty? && input_finished? end - alias :eof input_finished? - alias :eof? input_finished? + alias_method :eof?, :eof private - def internal_produce_input(buf = '') + def produce_input retried = 0 begin - @zlib_inflater.inflate(@decrypter.decrypt(@input_stream.read(Decompressor::CHUNK_SIZE, buf))) + @zlib_inflater.inflate(input_stream.read(Decompressor::CHUNK_SIZE)) rescue Zlib::BufError raise if retried >= 5 # how many times should we retry? retried += 1 retry end + rescue Zlib::Error => e + raise(::Zip::DecompressionError, 'zlib error while inflating') end - def internal_input_finished? + def input_finished? @zlib_inflater.finished? end - - def value_when_finished # mimic behaviour of ruby File object. - return if @has_returned_empty_string - @has_returned_empty_string = true - '' - end end + + ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_DEFLATE, ::Zip::Inflater) end # Copyright (C) 2002, 2003 Thomas Sondergaard diff --git a/lib/zip/input_stream.rb b/lib/zip/input_stream.rb index b9c35111..b4c502f5 100644 --- a/lib/zip/input_stream.rb +++ b/lib/zip/input_stream.rb @@ -39,6 +39,8 @@ module Zip # class. class InputStream + CHUNK_SIZE = 32_768 + include ::Zip::IOExtras::AbstractInputStream # Opens the indicated zip file. An exception is thrown @@ -78,16 +80,10 @@ def rewind end # Modeled after IO.sysread - def sysread(number_of_bytes = nil, buf = nil) - @decompressor.sysread(number_of_bytes, buf) - end - - def eof - @output_buffer.empty? && @decompressor.eof + def sysread(length = nil, outbuf = '') + @decompressor.read(length, outbuf) end - alias :eof? eof - class << self # Same as #initialize but if a block is passed the opened # stream is passed to the block and closed when the block @@ -124,46 +120,54 @@ def get_io(io_or_file, offset = 0) def open_entry @current_entry = ::Zip::Entry.read_local_entry(@archive_io) - if @current_entry && @current_entry.gp_flags & 1 == 1 && @decrypter.is_a?(NullEncrypter) + if @current_entry && @current_entry.encrypted? && @decrypter.is_a?(NullEncrypter) raise Error, 'password required to decode zip file' end - if @current_entry && @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 \ + if @current_entry && @current_entry.incomplete? && @current_entry.crc == 0 \ && @current_entry.compressed_size == 0 \ && @current_entry.size == 0 && !@complete_entry raise GPFBit3Error, 'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \ 'Please use ::Zip::File instead of ::Zip::InputStream' end + @decrypted_io = get_decrypted_io @decompressor = get_decompressor flush @current_entry end + def get_decrypted_io + header = @archive_io.read(@decrypter.header_bytesize) + @decrypter.reset!(header) + + ::Zip::DecryptedIo.new(@archive_io, @decrypter) + end + def get_decompressor - if @current_entry.nil? - ::Zip::NullDecompressor - elsif @current_entry.compression_method == ::Zip::Entry::STORED - if @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry - ::Zip::PassThruDecompressor.new(@archive_io, @complete_entry.size) + return ::Zip::NullDecompressor if @current_entry.nil? + + decompressed_size = + if @current_entry.incomplete? && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry + @complete_entry.size else - ::Zip::PassThruDecompressor.new(@archive_io, @current_entry.size) + @current_entry.size end - elsif @current_entry.compression_method == ::Zip::Entry::DEFLATED - header = @archive_io.read(@decrypter.header_bytesize) - @decrypter.reset!(header) - ::Zip::Inflater.new(@archive_io, @decrypter) - else + + decompressor_class = ::Zip::Decompressor.find_by_compression_method(@current_entry.compression_method) + if decompressor_class.nil? raise ::Zip::CompressionMethodError, "Unsupported compression method #{@current_entry.compression_method}" end + + decompressor_class.new(@decrypted_io, decompressed_size) end def produce_input - @decompressor.produce_input + @decompressor.read(CHUNK_SIZE) end def input_finished? - @decompressor.input_finished? + @decompressor.eof end end end diff --git a/lib/zip/ioextras/abstract_input_stream.rb b/lib/zip/ioextras/abstract_input_stream.rb index 7b7fd61d..58678a3f 100644 --- a/lib/zip/ioextras/abstract_input_stream.rb +++ b/lib/zip/ioextras/abstract_input_stream.rb @@ -106,6 +106,12 @@ def each_line(a_sep_string = $/) end alias_method :each, :each_line + + def eof + @output_buffer.empty? && input_finished? + end + + alias_method :eof?, :eof end end end diff --git a/lib/zip/null_decompressor.rb b/lib/zip/null_decompressor.rb index 1560ef14..6534b161 100644 --- a/lib/zip/null_decompressor.rb +++ b/lib/zip/null_decompressor.rb @@ -2,18 +2,10 @@ module Zip module NullDecompressor #:nodoc:all module_function - def sysread(_numberOfBytes = nil, _buf = nil) + def read(_length = nil, _outbuf = nil) nil end - def produce_input - nil - end - - def input_finished? - true - end - def eof true end diff --git a/lib/zip/pass_thru_decompressor.rb b/lib/zip/pass_thru_decompressor.rb index 485462c5..ac21b61e 100644 --- a/lib/zip/pass_thru_decompressor.rb +++ b/lib/zip/pass_thru_decompressor.rb @@ -1,38 +1,29 @@ module Zip class PassThruDecompressor < Decompressor #:nodoc:all - def initialize(input_stream, chars_to_read) - super(input_stream) - @chars_to_read = chars_to_read + def initialize(*args) + super @read_so_far = 0 - @has_returned_empty_string = false end - def sysread(number_of_bytes = nil, buf = '') - if input_finished? - has_returned_empty_string_val = @has_returned_empty_string - @has_returned_empty_string = true - return '' unless has_returned_empty_string_val - return - end + def read(length = nil, outbuf = '') + return ((length.nil? || length.zero?) ? "" : nil) if eof - if number_of_bytes.nil? || @read_so_far + number_of_bytes > @chars_to_read - number_of_bytes = @chars_to_read - @read_so_far + if length.nil? || (@read_so_far + length) > decompressed_size + length = decompressed_size - @read_so_far end - @read_so_far += number_of_bytes - @input_stream.read(number_of_bytes, buf) - end - def produce_input - sysread(::Zip::Decompressor::CHUNK_SIZE) + @read_so_far += length + input_stream.read(length, outbuf) end - def input_finished? - @read_so_far >= @chars_to_read + def eof + @read_so_far >= decompressed_size end - alias eof input_finished? - alias eof? input_finished? + alias_method :eof?, :eof end + + ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor) end # Copyright (C) 2002, 2003 Thomas Sondergaard diff --git a/test/bzip2_support_test.rb b/test/bzip2_support_test.rb new file mode 100644 index 00000000..ab86b4e8 --- /dev/null +++ b/test/bzip2_support_test.rb @@ -0,0 +1,11 @@ +require 'test_helper' + +class Bzip2SupportTest < MiniTest::Test + BZIP2_ZIP_TEST_FILE = 'test/data/zipWithBzip2Compression.zip' + + def test_read + Zip::InputStream.open(BZIP2_ZIP_TEST_FILE) do |zis| + assert_raises(Zip::CompressionMethodError) { zis.get_next_entry } + end + end +end diff --git a/test/constants_test.rb b/test/constants_test.rb new file mode 100644 index 00000000..8be01715 --- /dev/null +++ b/test/constants_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' + +class ConstantsTest < MiniTest::Test + def test_compression_methods + assert_equal(0, Zip::COMPRESSION_METHOD_STORE) + assert_equal(1, Zip::COMPRESSION_METHOD_SHRINK) + assert_equal(2, Zip::COMPRESSION_METHOD_REDUCE_1) + assert_equal(3, Zip::COMPRESSION_METHOD_REDUCE_2) + assert_equal(4, Zip::COMPRESSION_METHOD_REDUCE_3) + assert_equal(5, Zip::COMPRESSION_METHOD_REDUCE_4) + assert_equal(6, Zip::COMPRESSION_METHOD_IMPLODE) + assert_equal(8, Zip::COMPRESSION_METHOD_DEFLATE) + assert_equal(9, Zip::COMPRESSION_METHOD_DEFLATE_64) + assert_equal(10, Zip::COMPRESSION_METHOD_PKWARE_DCLI) + assert_equal(12, Zip::COMPRESSION_METHOD_BZIP2) + assert_equal(14, Zip::COMPRESSION_METHOD_LZMA) + assert_equal(16, Zip::COMPRESSION_METHOD_IBM_CMPSC) + assert_equal(18, Zip::COMPRESSION_METHOD_IBM_TERSE) + assert_equal(19, Zip::COMPRESSION_METHOD_IBM_LZ77) + assert_equal(96, Zip::COMPRESSION_METHOD_JPEG) + assert_equal(97, Zip::COMPRESSION_METHOD_WAVPACK) + assert_equal(98, Zip::COMPRESSION_METHOD_PPMD) + assert_equal(99, Zip::COMPRESSION_METHOD_AES) + + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_STORE]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_SHRINK]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_REDUCE_1]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_REDUCE_2]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_REDUCE_3]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_REDUCE_4]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_IMPLODE]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_DEFLATE]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_DEFLATE_64]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_PKWARE_DCLI]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_BZIP2]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_LZMA]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_IBM_CMPSC]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_IBM_TERSE]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_IBM_LZ77]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_JPEG]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_WAVPACK]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_PPMD]) + assert(Zip::COMPRESSION_METHODS[Zip::COMPRESSION_METHOD_AES]) + end +end diff --git a/test/data/file1.txt.corrupt.deflatedData b/test/data/file1.txt.corrupt.deflatedData new file mode 100644 index 00000000..95fe8720 Binary files /dev/null and b/test/data/file1.txt.corrupt.deflatedData differ diff --git a/test/data/zipWithBzip2Compression.zip b/test/data/zipWithBzip2Compression.zip new file mode 100644 index 00000000..1cd268b3 Binary files /dev/null and b/test/data/zipWithBzip2Compression.zip differ diff --git a/test/data/zipWithStoredCompression.zip b/test/data/zipWithStoredCompression.zip new file mode 100644 index 00000000..045ab9d4 Binary files /dev/null and b/test/data/zipWithStoredCompression.zip differ diff --git a/test/data/zipWithStoredCompressionAndEncryption.zip b/test/data/zipWithStoredCompressionAndEncryption.zip new file mode 100644 index 00000000..2fd545e9 Binary files /dev/null and b/test/data/zipWithStoredCompressionAndEncryption.zip differ diff --git a/test/decompressor_test.rb b/test/decompressor_test.rb new file mode 100644 index 00000000..d7ff2e73 --- /dev/null +++ b/test/decompressor_test.rb @@ -0,0 +1,15 @@ +require 'test_helper' +class DecompressorTest < MiniTest::Test + TEST_COMPRESSION_METHOD = 255 + + class TestCompressionClass + end + + def test_decompressor_registration + assert_nil(::Zip::Decompressor.find_by_compression_method(TEST_COMPRESSION_METHOD)) + + ::Zip::Decompressor.register(TEST_COMPRESSION_METHOD, TestCompressionClass) + + assert_equal(TestCompressionClass, ::Zip::Decompressor.find_by_compression_method(TEST_COMPRESSION_METHOD)) + end +end diff --git a/test/deflater_test.rb b/test/deflater_test.rb index e4f552ef..d1970ce9 100644 --- a/test/deflater_test.rb +++ b/test/deflater_test.rb @@ -34,11 +34,16 @@ def test_default_compression assert(default < no) end + def test_data_error + assert_raises(::Zip::DecompressionError) do + inflate('test/data/file1.txt.corrupt.deflatedData') + end + end + private def load_file(fileName) - txt = nil - File.open(fileName, 'rb') { |f| txt = f.read } + File.open(fileName, 'rb') { |f| f.read } end def deflate(data, fileName) @@ -52,10 +57,9 @@ def deflate(data, fileName) end def inflate(fileName) - txt = nil File.open(fileName, 'rb') do |file| inflater = ::Zip::Inflater.new(file) - txt = inflater.sysread + inflater.read end end diff --git a/test/entry_test.rb b/test/entry_test.rb index b49783d3..8daf7adc 100644 --- a/test/entry_test.rb +++ b/test/entry_test.rb @@ -151,4 +151,22 @@ def test_store_file_without_compression assert_match(/mimetypeapplication\/epub\+zip/, first_100_bytes) end + + def test_encrypted? + entry = Zip::Entry.new + entry.gp_flags = 1 + assert_equal(true, entry.encrypted?) + + entry.gp_flags = 0 + assert_equal(false, entry.encrypted?) + end + + def test_incomplete? + entry = Zip::Entry.new + entry.gp_flags = 8 + assert_equal(true, entry.incomplete?) + + entry.gp_flags = 0 + assert_equal(false, entry.incomplete?) + end end diff --git a/test/stored_support_test.rb b/test/stored_support_test.rb new file mode 100644 index 00000000..8260e4a9 --- /dev/null +++ b/test/stored_support_test.rb @@ -0,0 +1,34 @@ +require 'test_helper' + +class StoredSupportTest < MiniTest::Test + STORED_ZIP_TEST_FILE = 'test/data/zipWithStoredCompression.zip' + ENCRYPTED_STORED_ZIP_TEST_FILE = 'test/data/zipWithStoredCompressionAndEncryption.zip' + INPUT_FILE1 = 'test/data/file1.txt' + INPUT_FILE2 = 'test/data/file2.txt' + + def test_read + Zip::InputStream.open(STORED_ZIP_TEST_FILE) do |zis| + entry = zis.get_next_entry + assert_equal 'file1.txt', entry.name + assert_equal 1327, entry.size + assert_equal open(INPUT_FILE1, 'r').read, zis.read + entry = zis.get_next_entry + assert_equal 'file2.txt', entry.name + assert_equal 41234, entry.size + assert_equal open(INPUT_FILE2, 'r').read, zis.read + end + end + + def test_encrypted_read + Zip::InputStream.open(ENCRYPTED_STORED_ZIP_TEST_FILE, 0, Zip::TraditionalDecrypter.new('password')) do |zis| + entry = zis.get_next_entry + assert_equal 'file1.txt', entry.name + assert_equal 1327, entry.size + assert_equal open(INPUT_FILE1, 'r').read, zis.read + entry = zis.get_next_entry + assert_equal 'file2.txt', entry.name + assert_equal 41234, entry.size + assert_equal open(INPUT_FILE2, 'r').read, zis.read + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 6d11af6c..224a1eb2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -66,28 +66,16 @@ def setup end def test_read_everything - assert_equal(@refText, @decompressor.sysread) + assert_equal(@refText, @decompressor.read) end def test_read_in_chunks chunkSize = 5 - while (decompressedChunk = @decompressor.sysread(chunkSize)) + while (decompressedChunk = @decompressor.read(chunkSize)) assert_equal(@refText.slice!(0, chunkSize), decompressedChunk) end assert_equal(0, @refText.size) end - - def test_mixing_reads_and_produce_input - # Just some preconditions to make sure we have enough data for this test - assert(@refText.length > 1000) - assert(@refLines.length > 40) - - assert_equal(@refText[0...100], @decompressor.sysread(100)) - - assert(!@decompressor.input_finished?) - buf = @decompressor.produce_input - assert_equal(@refText[100...(100 + buf.length)], buf) - end end module AssertEntry