rubyzip 1.2.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +64 -23
- data/lib/zip.rb +5 -3
- data/lib/zip/constants.rb +52 -0
- data/lib/zip/crypto/decrypted_io.rb +39 -0
- data/lib/zip/decompressor.rb +19 -1
- data/lib/zip/dos_time.rb +5 -0
- data/lib/zip/entry.rb +34 -10
- data/lib/zip/errors.rb +2 -0
- data/lib/zip/extra_field/generic.rb +1 -1
- data/lib/zip/extra_field/universal_time.rb +39 -12
- data/lib/zip/file.rb +68 -34
- data/lib/zip/inflater.rb +22 -36
- data/lib/zip/input_stream.rb +28 -24
- data/lib/zip/ioextras/abstract_input_stream.rb +6 -0
- data/lib/zip/null_decompressor.rb +1 -9
- data/lib/zip/pass_thru_decompressor.rb +13 -22
- data/lib/zip/streamable_stream.rb +1 -6
- data/lib/zip/version.rb +1 -1
- metadata +12 -154
- data/test/basic_zip_file_test.rb +0 -60
- data/test/case_sensitivity_test.rb +0 -69
- data/test/central_directory_entry_test.rb +0 -69
- data/test/central_directory_test.rb +0 -100
- data/test/crypto/null_encryption_test.rb +0 -57
- data/test/crypto/traditional_encryption_test.rb +0 -80
- data/test/data/WarnInvalidDate.zip +0 -0
- data/test/data/file1.txt +0 -46
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +0 -1504
- data/test/data/globTest.zip +0 -0
- data/test/data/globTest/foo.txt +0 -0
- data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
- data/test/data/globTest/food.txt +0 -0
- data/test/data/gpbit3stored.zip +0 -0
- data/test/data/mimetype +0 -1
- data/test/data/notzippedruby.rb +0 -7
- data/test/data/ntfs.zip +0 -0
- data/test/data/oddExtraField.zip +0 -0
- data/test/data/path_traversal/Makefile +0 -10
- data/test/data/path_traversal/jwilk/README.md +0 -5
- data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
- data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
- data/test/data/path_traversal/jwilk/relative0.zip +0 -0
- data/test/data/path_traversal/jwilk/relative2.zip +0 -0
- data/test/data/path_traversal/jwilk/symlink.zip +0 -0
- data/test/data/path_traversal/relative1.zip +0 -0
- data/test/data/path_traversal/tilde.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
- data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/test.xls +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zip64-sample.zip +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/data/zipWithEncryption.zip +0 -0
- data/test/deflater_test.rb +0 -65
- data/test/encryption_test.rb +0 -42
- data/test/entry_set_test.rb +0 -163
- data/test/entry_test.rb +0 -154
- data/test/errors_test.rb +0 -35
- data/test/extra_field_test.rb +0 -76
- data/test/file_extract_directory_test.rb +0 -54
- data/test/file_extract_test.rb +0 -83
- data/test/file_permissions_test.rb +0 -65
- data/test/file_split_test.rb +0 -57
- data/test/file_test.rb +0 -601
- data/test/filesystem/dir_iterator_test.rb +0 -58
- data/test/filesystem/directory_test.rb +0 -139
- data/test/filesystem/file_mutating_test.rb +0 -87
- data/test/filesystem/file_nonmutating_test.rb +0 -508
- data/test/filesystem/file_stat_test.rb +0 -64
- data/test/gentestfiles.rb +0 -126
- data/test/inflater_test.rb +0 -14
- data/test/input_stream_test.rb +0 -182
- data/test/ioextras/abstract_input_stream_test.rb +0 -102
- data/test/ioextras/abstract_output_stream_test.rb +0 -106
- data/test/ioextras/fake_io_test.rb +0 -18
- data/test/local_entry_test.rb +0 -154
- data/test/output_stream_test.rb +0 -128
- data/test/pass_thru_compressor_test.rb +0 -30
- data/test/pass_thru_decompressor_test.rb +0 -14
- data/test/path_traversal_test.rb +0 -141
- data/test/samples/example_recursive_test.rb +0 -37
- data/test/settings_test.rb +0 -95
- data/test/test_helper.rb +0 -234
- data/test/unicode_file_names_and_comments_test.rb +0 -62
- data/test/zip64_full_test.rb +0 -51
- data/test/zip64_support_test.rb +0 -14
data/lib/zip/errors.rb
CHANGED
@@ -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
|
-
|
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 =
|
12
|
-
|
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
|
-
|
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 ||
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
70
|
+
s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
|
44
71
|
s
|
45
72
|
end
|
46
73
|
end
|
data/lib/zip/file.rb
CHANGED
@@ -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
|
-
|
64
|
+
|
65
|
+
# default -> false, but will be set to true in a future version.
|
59
66
|
attr_accessor :restore_permissions
|
60
|
-
|
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(
|
76
|
+
def initialize(path_or_io, create = false, buffer = false, options = {})
|
68
77
|
super()
|
69
|
-
|
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
|
-
|
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(
|
75
|
-
|
76
|
-
|
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?(
|
81
|
-
|
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
|
-
|
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]
|
88
|
-
@restore_permissions = options[:restore_permissions]
|
89
|
-
@restore_times = options[:restore_times]
|
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
|
-
#
|
94
|
-
# to the block and is automatically closed afterwards just as with
|
95
|
-
# ruby's builtin File
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
362
|
-
|
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
|
|
data/lib/zip/inflater.rb
CHANGED
@@ -1,64 +1,50 @@
|
|
1
1
|
module Zip
|
2
2
|
class Inflater < Decompressor #:nodoc:all
|
3
|
-
def initialize(
|
4
|
-
super
|
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
|
-
|
12
|
-
|
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
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
37
|
-
alias :eof? input_finished?
|
25
|
+
alias_method :eof?, :eof
|
38
26
|
|
39
27
|
private
|
40
28
|
|
41
|
-
def
|
29
|
+
def produce_input
|
42
30
|
retried = 0
|
43
31
|
begin
|
44
|
-
@zlib_inflater.inflate(
|
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
|
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
|
data/lib/zip/input_stream.rb
CHANGED
@@ -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(
|
82
|
-
@decompressor.
|
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
|
-
|
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.
|
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.
|
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
|
-
|
145
|
-
|
146
|
-
if @current_entry.
|
147
|
-
|
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
|
-
|
153
|
+
@current_entry.size
|
150
154
|
end
|
151
|
-
|
152
|
-
|
153
|
-
|
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.
|
166
|
+
@decompressor.read(CHUNK_SIZE)
|
163
167
|
end
|
164
168
|
|
165
169
|
def input_finished?
|
166
|
-
@decompressor.
|
170
|
+
@decompressor.eof
|
167
171
|
end
|
168
172
|
end
|
169
173
|
end
|