rubyzip 1.2.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +64 -23
  3. data/lib/zip.rb +5 -3
  4. data/lib/zip/constants.rb +52 -0
  5. data/lib/zip/crypto/decrypted_io.rb +39 -0
  6. data/lib/zip/decompressor.rb +19 -1
  7. data/lib/zip/dos_time.rb +5 -0
  8. data/lib/zip/entry.rb +34 -10
  9. data/lib/zip/errors.rb +2 -0
  10. data/lib/zip/extra_field/generic.rb +1 -1
  11. data/lib/zip/extra_field/universal_time.rb +39 -12
  12. data/lib/zip/file.rb +68 -34
  13. data/lib/zip/inflater.rb +22 -36
  14. data/lib/zip/input_stream.rb +28 -24
  15. data/lib/zip/ioextras/abstract_input_stream.rb +6 -0
  16. data/lib/zip/null_decompressor.rb +1 -9
  17. data/lib/zip/pass_thru_decompressor.rb +13 -22
  18. data/lib/zip/streamable_stream.rb +1 -6
  19. data/lib/zip/version.rb +1 -1
  20. metadata +12 -154
  21. data/test/basic_zip_file_test.rb +0 -60
  22. data/test/case_sensitivity_test.rb +0 -69
  23. data/test/central_directory_entry_test.rb +0 -69
  24. data/test/central_directory_test.rb +0 -100
  25. data/test/crypto/null_encryption_test.rb +0 -57
  26. data/test/crypto/traditional_encryption_test.rb +0 -80
  27. data/test/data/WarnInvalidDate.zip +0 -0
  28. data/test/data/file1.txt +0 -46
  29. data/test/data/file1.txt.deflatedData +0 -0
  30. data/test/data/file2.txt +0 -1504
  31. data/test/data/globTest.zip +0 -0
  32. data/test/data/globTest/foo.txt +0 -0
  33. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  34. data/test/data/globTest/food.txt +0 -0
  35. data/test/data/gpbit3stored.zip +0 -0
  36. data/test/data/mimetype +0 -1
  37. data/test/data/notzippedruby.rb +0 -7
  38. data/test/data/ntfs.zip +0 -0
  39. data/test/data/oddExtraField.zip +0 -0
  40. data/test/data/path_traversal/Makefile +0 -10
  41. data/test/data/path_traversal/jwilk/README.md +0 -5
  42. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  43. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  44. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  45. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  46. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  47. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  48. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  49. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  50. data/test/data/path_traversal/relative1.zip +0 -0
  51. data/test/data/path_traversal/tilde.zip +0 -0
  52. data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
  53. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  54. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  55. data/test/data/rubycode.zip +0 -0
  56. data/test/data/rubycode2.zip +0 -0
  57. data/test/data/test.xls +0 -0
  58. data/test/data/testDirectory.bin +0 -0
  59. data/test/data/zip64-sample.zip +0 -0
  60. data/test/data/zipWithDirs.zip +0 -0
  61. data/test/data/zipWithEncryption.zip +0 -0
  62. data/test/deflater_test.rb +0 -65
  63. data/test/encryption_test.rb +0 -42
  64. data/test/entry_set_test.rb +0 -163
  65. data/test/entry_test.rb +0 -154
  66. data/test/errors_test.rb +0 -35
  67. data/test/extra_field_test.rb +0 -76
  68. data/test/file_extract_directory_test.rb +0 -54
  69. data/test/file_extract_test.rb +0 -83
  70. data/test/file_permissions_test.rb +0 -65
  71. data/test/file_split_test.rb +0 -57
  72. data/test/file_test.rb +0 -601
  73. data/test/filesystem/dir_iterator_test.rb +0 -58
  74. data/test/filesystem/directory_test.rb +0 -139
  75. data/test/filesystem/file_mutating_test.rb +0 -87
  76. data/test/filesystem/file_nonmutating_test.rb +0 -508
  77. data/test/filesystem/file_stat_test.rb +0 -64
  78. data/test/gentestfiles.rb +0 -126
  79. data/test/inflater_test.rb +0 -14
  80. data/test/input_stream_test.rb +0 -182
  81. data/test/ioextras/abstract_input_stream_test.rb +0 -102
  82. data/test/ioextras/abstract_output_stream_test.rb +0 -106
  83. data/test/ioextras/fake_io_test.rb +0 -18
  84. data/test/local_entry_test.rb +0 -154
  85. data/test/output_stream_test.rb +0 -128
  86. data/test/pass_thru_compressor_test.rb +0 -30
  87. data/test/pass_thru_decompressor_test.rb +0 -14
  88. data/test/path_traversal_test.rb +0 -141
  89. data/test/samples/example_recursive_test.rb +0 -37
  90. data/test/settings_test.rb +0 -95
  91. data/test/test_helper.rb +0 -234
  92. data/test/unicode_file_names_and_comments_test.rb +0 -62
  93. data/test/zip64_full_test.rb +0 -51
  94. data/test/zip64_support_test.rb +0 -14
@@ -4,8 +4,10 @@ module Zip
4
4
  class DestinationFileExistsError < Error; end
5
5
  class CompressionMethodError < Error; end
6
6
  class EntryNameError < Error; end
7
+ class EntrySizeError < Error; end
7
8
  class InternalError < Error; end
8
9
  class GPFBit3Error < Error; end
10
+ class DecompressionError < Error; end
9
11
 
10
12
  # Backwards compatibility with v1 (delete in v2)
11
13
  ZipError = Error
@@ -16,7 +16,7 @@ module Zip
16
16
  # If nil, start with empty.
17
17
  return false
18
18
  elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
19
- $stderr.puts 'Warning: weired extra feild header ID. skip parsing'
19
+ warn 'WARNING: weird extra field header ID. Skip parsing it.'
20
20
  return false
21
21
  end
22
22
  [binstr[2, 2].unpack('v')[0], binstr[4..-1]]
@@ -4,24 +4,51 @@ module Zip
4
4
  HEADER_ID = 'UT'
5
5
  register_map
6
6
 
7
+ ATIME_MASK = 0b010
8
+ CTIME_MASK = 0b100
9
+ MTIME_MASK = 0b001
10
+
7
11
  def initialize(binstr = nil)
8
12
  @ctime = nil
9
13
  @mtime = nil
10
14
  @atime = nil
11
- @flag = nil
12
- binstr && merge(binstr)
15
+ @flag = 0
16
+
17
+ merge(binstr) unless binstr.nil?
18
+ end
19
+
20
+ attr_reader :atime, :ctime, :mtime, :flag
21
+
22
+ def atime=(time)
23
+ @flag = time.nil? ? @flag & ~ATIME_MASK : @flag | ATIME_MASK
24
+ @atime = time
13
25
  end
14
26
 
15
- attr_accessor :atime, :ctime, :mtime, :flag
27
+ def ctime=(time)
28
+ @flag = time.nil? ? @flag & ~CTIME_MASK : @flag | CTIME_MASK
29
+ @ctime = time
30
+ end
31
+
32
+ def mtime=(time)
33
+ @flag = time.nil? ? @flag & ~MTIME_MASK : @flag | MTIME_MASK
34
+ @mtime = time
35
+ end
16
36
 
17
37
  def merge(binstr)
18
38
  return if binstr.empty?
39
+
19
40
  size, content = initial_parse(binstr)
20
- size || return
21
- @flag, mtime, atime, ctime = content.unpack('CVVV')
22
- mtime && @mtime ||= ::Zip::DOSTime.at(mtime)
23
- atime && @atime ||= ::Zip::DOSTime.at(atime)
24
- ctime && @ctime ||= ::Zip::DOSTime.at(ctime)
41
+ return if !size || size <= 0
42
+
43
+ @flag, *times = content.unpack('Cl<l<l<')
44
+
45
+ # Parse the timestamps, in order, based on which flags are set.
46
+ return if times[0].nil?
47
+ @mtime ||= ::Zip::DOSTime.at(times.shift) unless @flag & MTIME_MASK == 0
48
+ return if times[0].nil?
49
+ @atime ||= ::Zip::DOSTime.at(times.shift) unless @flag & ATIME_MASK == 0
50
+ return if times[0].nil?
51
+ @ctime ||= ::Zip::DOSTime.at(times.shift) unless @flag & CTIME_MASK == 0
25
52
  end
26
53
 
27
54
  def ==(other)
@@ -32,15 +59,15 @@ module Zip
32
59
 
33
60
  def pack_for_local
34
61
  s = [@flag].pack('C')
35
- @flag & 1 != 0 && s << [@mtime.to_i].pack('V')
36
- @flag & 2 != 0 && s << [@atime.to_i].pack('V')
37
- @flag & 4 != 0 && s << [@ctime.to_i].pack('V')
62
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
63
+ s << [@atime.to_i].pack('l<') unless @flag & ATIME_MASK == 0
64
+ s << [@ctime.to_i].pack('l<') unless @flag & CTIME_MASK == 0
38
65
  s
39
66
  end
40
67
 
41
68
  def pack_for_c_dir
42
69
  s = [@flag].pack('C')
43
- @flag & 1 == 1 && s << [@mtime.to_i].pack('V')
70
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
44
71
  s
45
72
  end
46
73
  end
@@ -49,52 +49,76 @@ module Zip
49
49
  MAX_SEGMENT_SIZE = 3_221_225_472
50
50
  MIN_SEGMENT_SIZE = 65_536
51
51
  DATA_BUFFER_SIZE = 8192
52
- IO_METHODS = [:tell, :seek, :read, :close]
52
+ IO_METHODS = [:tell, :seek, :read, :eof, :close]
53
+
54
+ DEFAULT_OPTIONS = {
55
+ restore_ownership: false,
56
+ restore_permissions: false,
57
+ restore_times: false
58
+ }.freeze
53
59
 
54
60
  attr_reader :name
55
61
 
56
- # default -> false
62
+ # default -> false.
57
63
  attr_accessor :restore_ownership
58
- # default -> false
64
+
65
+ # default -> false, but will be set to true in a future version.
59
66
  attr_accessor :restore_permissions
60
- # default -> true
67
+
68
+ # default -> false, but will be set to true in a future version.
61
69
  attr_accessor :restore_times
70
+
62
71
  # Returns the zip files comment, if it has one
63
72
  attr_accessor :comment
64
73
 
65
74
  # Opens a zip archive. Pass true as the second parameter to create
66
75
  # a new archive if it doesn't exist already.
67
- def initialize(file_name, create = false, buffer = false, options = {})
76
+ def initialize(path_or_io, create = false, buffer = false, options = {})
68
77
  super()
69
- @name = file_name
78
+ options = DEFAULT_OPTIONS.merge(options)
79
+ @name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
70
80
  @comment = ''
71
81
  @create = create ? true : false # allow any truthy value to mean true
72
- if !buffer && ::File.size?(file_name)
82
+
83
+ if ::File.size?(@name.to_s)
84
+ # There is a file, which exists, that is associated with this zip.
73
85
  @create = false
74
- @file_permissions = ::File.stat(file_name).mode
75
- ::File.open(name, 'rb') do |f|
76
- read_from_stream(f)
86
+ @file_permissions = ::File.stat(@name).mode
87
+
88
+ if buffer
89
+ read_from_stream(path_or_io)
90
+ else
91
+ ::File.open(@name, 'rb') do |f|
92
+ read_from_stream(f)
93
+ end
77
94
  end
95
+ elsif buffer && path_or_io.size > 0
96
+ # This zip is probably a non-empty StringIO.
97
+ read_from_stream(path_or_io)
78
98
  elsif @create
99
+ # This zip is completely new/empty and is to be created.
79
100
  @entry_set = EntrySet.new
80
- elsif ::File.zero?(file_name)
81
- raise Error, "File #{file_name} has zero size. Did you mean to pass the create flag?"
101
+ elsif ::File.zero?(@name)
102
+ # A file exists, but it is empty.
103
+ raise Error, "File #{@name} has zero size. Did you mean to pass the create flag?"
82
104
  else
83
- raise Error, "File #{file_name} not found"
105
+ # Everything is wrong.
106
+ raise Error, "File #{@name} not found"
84
107
  end
108
+
85
109
  @stored_entries = @entry_set.dup
86
110
  @stored_comment = @comment
87
- @restore_ownership = options[:restore_ownership] || false
88
- @restore_permissions = options[:restore_permissions] || true
89
- @restore_times = options[:restore_times] || true
111
+ @restore_ownership = options[:restore_ownership]
112
+ @restore_permissions = options[:restore_permissions]
113
+ @restore_times = options[:restore_times]
90
114
  end
91
115
 
92
116
  class << self
93
- # Same as #new. If a block is passed the ZipFile object is passed
94
- # to the block and is automatically closed afterwards just as with
95
- # ruby's builtin File.open method.
96
- def open(file_name, create = false)
97
- zf = ::Zip::File.new(file_name, create)
117
+ # Similar to ::new. If a block is passed the Zip::File object is passed
118
+ # to the block and is automatically closed afterwards, just as with
119
+ # ruby's builtin File::open method.
120
+ def open(file_name, create = false, options = {})
121
+ zf = ::Zip::File.new(file_name, create, false, options)
98
122
  return zf unless block_given?
99
123
  begin
100
124
  yield zf
@@ -119,17 +143,16 @@ module Zip
119
143
  unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
120
144
  raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
121
145
  end
122
- if io.is_a?(::String)
123
- require 'stringio'
124
- io = ::StringIO.new(io)
125
- elsif io.respond_to?(:binmode)
126
- # https://github.com/rubyzip/rubyzip/issues/119
127
- io.binmode
128
- end
146
+
147
+ io = ::StringIO.new(io) if io.is_a?(::String)
148
+
149
+ # https://github.com/rubyzip/rubyzip/issues/119
150
+ io.binmode if io.respond_to?(:binmode)
151
+
129
152
  zf = ::Zip::File.new(io, true, true, options)
130
- zf.read_from_stream(io)
131
153
  return zf unless block_given?
132
154
  yield zf
155
+
133
156
  begin
134
157
  zf.write_buffer(io)
135
158
  rescue IOError => e
@@ -274,6 +297,13 @@ module Zip
274
297
  @entry_set << new_entry
275
298
  end
276
299
 
300
+ # Convenience method for adding the contents of a file to the archive
301
+ # in Stored format (uncompressed)
302
+ def add_stored(entry, src_path, &continue_on_exists_proc)
303
+ entry = ::Zip::Entry.new(@name, entry.to_s, nil, nil, nil, nil, ::Zip::Entry::STORED)
304
+ add(entry, src_path, &continue_on_exists_proc)
305
+ end
306
+
277
307
  # Removes the specified entry.
278
308
  def remove(entry)
279
309
  @entry_set.delete(get_entry(entry))
@@ -346,7 +376,13 @@ module Zip
346
376
  # Searches for entry with the specified name. Returns nil if
347
377
  # no entry is found. See also get_entry
348
378
  def find_entry(entry_name)
349
- @entry_set.find_entry(entry_name)
379
+ selected_entry = @entry_set.find_entry(entry_name)
380
+ return if selected_entry.nil?
381
+
382
+ selected_entry.restore_ownership = @restore_ownership
383
+ selected_entry.restore_permissions = @restore_permissions
384
+ selected_entry.restore_times = @restore_times
385
+ selected_entry
350
386
  end
351
387
 
352
388
  # Searches for entries given a glob
@@ -358,10 +394,8 @@ module Zip
358
394
  # if no entry is found.
359
395
  def get_entry(entry)
360
396
  selected_entry = find_entry(entry)
361
- raise Errno::ENOENT, entry unless selected_entry
362
- selected_entry.restore_ownership = @restore_ownership
363
- selected_entry.restore_permissions = @restore_permissions
364
- selected_entry.restore_times = @restore_times
397
+ raise Errno::ENOENT, entry if selected_entry.nil?
398
+
365
399
  selected_entry
366
400
  end
367
401
 
@@ -1,64 +1,50 @@
1
1
  module Zip
2
2
  class Inflater < Decompressor #:nodoc:all
3
- def initialize(input_stream, decrypter = NullDecrypter.new)
4
- super(input_stream)
5
- @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
6
- @output_buffer = ''.dup
7
- @has_returned_empty_string = false
8
- @decrypter = decrypter
9
- end
3
+ def initialize(*args)
4
+ super
10
5
 
11
- def sysread(number_of_bytes = nil, buf = '')
12
- readEverything = number_of_bytes.nil?
13
- while readEverything || @output_buffer.bytesize < number_of_bytes
14
- break if internal_input_finished?
15
- @output_buffer << internal_produce_input(buf)
16
- end
17
- return value_when_finished if @output_buffer.bytesize == 0 && input_finished?
18
- end_index = number_of_bytes.nil? ? @output_buffer.bytesize : number_of_bytes
19
- @output_buffer.slice!(0...end_index)
6
+ @buffer = ''.dup
7
+ @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
20
8
  end
21
9
 
22
- def produce_input
23
- if @output_buffer.empty?
24
- internal_produce_input
25
- else
26
- @output_buffer.slice!(0...(@output_buffer.length))
10
+ def read(length = nil, outbuf = '')
11
+ return ((length.nil? || length.zero?) ? "" : nil) if eof
12
+
13
+ while length.nil? || (@buffer.bytesize < length)
14
+ break if input_finished?
15
+ @buffer << produce_input
27
16
  end
17
+
18
+ outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
28
19
  end
29
20
 
30
- # to be used with produce_input, not read (as read may still have more data cached)
31
- # is data cached anywhere other than @outputBuffer? the comment above may be wrong
32
- def input_finished?
33
- @output_buffer.empty? && internal_input_finished?
21
+ def eof
22
+ @buffer.empty? && input_finished?
34
23
  end
35
24
 
36
- alias :eof input_finished?
37
- alias :eof? input_finished?
25
+ alias_method :eof?, :eof
38
26
 
39
27
  private
40
28
 
41
- def internal_produce_input(buf = '')
29
+ def produce_input
42
30
  retried = 0
43
31
  begin
44
- @zlib_inflater.inflate(@decrypter.decrypt(@input_stream.read(Decompressor::CHUNK_SIZE, buf)))
32
+ @zlib_inflater.inflate(input_stream.read(Decompressor::CHUNK_SIZE))
45
33
  rescue Zlib::BufError
46
34
  raise if retried >= 5 # how many times should we retry?
47
35
  retried += 1
48
36
  retry
49
37
  end
38
+ rescue Zlib::Error
39
+ raise(::Zip::DecompressionError, 'zlib error while inflating')
50
40
  end
51
41
 
52
- def internal_input_finished?
42
+ def input_finished?
53
43
  @zlib_inflater.finished?
54
44
  end
55
-
56
- def value_when_finished # mimic behaviour of ruby File object.
57
- return if @has_returned_empty_string
58
- @has_returned_empty_string = true
59
- ''
60
- end
61
45
  end
46
+
47
+ ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_DEFLATE, ::Zip::Inflater)
62
48
  end
63
49
 
64
50
  # Copyright (C) 2002, 2003 Thomas Sondergaard
@@ -39,6 +39,8 @@ module Zip
39
39
  # class.
40
40
 
41
41
  class InputStream
42
+ CHUNK_SIZE = 32_768
43
+
42
44
  include ::Zip::IOExtras::AbstractInputStream
43
45
 
44
46
  # Opens the indicated zip file. An exception is thrown
@@ -78,16 +80,10 @@ module Zip
78
80
  end
79
81
 
80
82
  # Modeled after IO.sysread
81
- def sysread(number_of_bytes = nil, buf = nil)
82
- @decompressor.sysread(number_of_bytes, buf)
83
- end
84
-
85
- def eof
86
- @output_buffer.empty? && @decompressor.eof
83
+ def sysread(length = nil, outbuf = '')
84
+ @decompressor.read(length, outbuf)
87
85
  end
88
86
 
89
- alias :eof? eof
90
-
91
87
  class << self
92
88
  # Same as #initialize but if a block is passed the opened
93
89
  # stream is passed to the block and closed when the block
@@ -103,7 +99,7 @@ module Zip
103
99
  end
104
100
 
105
101
  def open_buffer(filename_or_io, offset = 0)
106
- puts 'open_buffer is deprecated!!! Use open instead!'
102
+ warn 'open_buffer is deprecated!!! Use open instead!'
107
103
  open(filename_or_io, offset)
108
104
  end
109
105
  end
@@ -124,46 +120,54 @@ module Zip
124
120
 
125
121
  def open_entry
126
122
  @current_entry = ::Zip::Entry.read_local_entry(@archive_io)
127
- if @current_entry && @current_entry.gp_flags & 1 == 1 && @decrypter.is_a?(NullEncrypter)
123
+ if @current_entry && @current_entry.encrypted? && @decrypter.is_a?(NullEncrypter)
128
124
  raise Error, 'password required to decode zip file'
129
125
  end
130
- if @current_entry && @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 \
126
+ if @current_entry && @current_entry.incomplete? && @current_entry.crc == 0 \
131
127
  && @current_entry.compressed_size == 0 \
132
128
  && @current_entry.size == 0 && !@complete_entry
133
129
  raise GPFBit3Error,
134
130
  'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
135
131
  'Please use ::Zip::File instead of ::Zip::InputStream'
136
132
  end
133
+ @decrypted_io = get_decrypted_io
137
134
  @decompressor = get_decompressor
138
135
  flush
139
136
  @current_entry
140
137
  end
141
138
 
139
+ def get_decrypted_io
140
+ header = @archive_io.read(@decrypter.header_bytesize)
141
+ @decrypter.reset!(header)
142
+
143
+ ::Zip::DecryptedIo.new(@archive_io, @decrypter)
144
+ end
145
+
142
146
  def get_decompressor
143
- if @current_entry.nil?
144
- ::Zip::NullDecompressor
145
- elsif @current_entry.compression_method == ::Zip::Entry::STORED
146
- if @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
147
- ::Zip::PassThruDecompressor.new(@archive_io, @complete_entry.size)
147
+ return ::Zip::NullDecompressor if @current_entry.nil?
148
+
149
+ decompressed_size =
150
+ if @current_entry.incomplete? && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
151
+ @complete_entry.size
148
152
  else
149
- ::Zip::PassThruDecompressor.new(@archive_io, @current_entry.size)
153
+ @current_entry.size
150
154
  end
151
- elsif @current_entry.compression_method == ::Zip::Entry::DEFLATED
152
- header = @archive_io.read(@decrypter.header_bytesize)
153
- @decrypter.reset!(header)
154
- ::Zip::Inflater.new(@archive_io, @decrypter)
155
- else
155
+
156
+ decompressor_class = ::Zip::Decompressor.find_by_compression_method(@current_entry.compression_method)
157
+ if decompressor_class.nil?
156
158
  raise ::Zip::CompressionMethodError,
157
159
  "Unsupported compression method #{@current_entry.compression_method}"
158
160
  end
161
+
162
+ decompressor_class.new(@decrypted_io, decompressed_size)
159
163
  end
160
164
 
161
165
  def produce_input
162
- @decompressor.produce_input
166
+ @decompressor.read(CHUNK_SIZE)
163
167
  end
164
168
 
165
169
  def input_finished?
166
- @decompressor.input_finished?
170
+ @decompressor.eof
167
171
  end
168
172
  end
169
173
  end