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.
- 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
|