rubyzip 3.0.2 → 3.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/Changelog.md +32 -0
- data/README.md +64 -13
- data/Rakefile +4 -6
- data/lib/zip/central_directory.rb +5 -3
- data/lib/zip/crypto/aes_encryption.rb +120 -0
- data/lib/zip/crypto/decrypted_io.rb +17 -13
- data/lib/zip/crypto/null_encryption.rb +0 -10
- data/lib/zip/crypto/traditional_encryption.rb +2 -0
- data/lib/zip/dos_time.rb +3 -2
- data/lib/zip/entry.rb +50 -26
- data/lib/zip/extra_field/aes.rb +50 -0
- data/lib/zip/extra_field/generic.rb +7 -1
- data/lib/zip/extra_field/unknown.rb +3 -1
- data/lib/zip/extra_field/zip64.rb +7 -0
- data/lib/zip/extra_field.rb +12 -4
- data/lib/zip/file.rb +26 -22
- data/lib/zip/filesystem/file.rb +7 -6
- data/lib/zip/filesystem/file_stat.rb +4 -4
- data/lib/zip/inflater.rb +4 -3
- data/lib/zip/input_stream.rb +31 -12
- data/lib/zip/ioextras/abstract_input_stream.rb +3 -2
- data/lib/zip/null_decompressor.rb +3 -2
- data/lib/zip/output_stream.rb +13 -9
- data/lib/zip/pass_thru_decompressor.rb +4 -3
- data/lib/zip/streamable_stream.rb +1 -1
- data/lib/zip/version.rb +2 -1
- data/lib/zip.rb +2 -0
- data/rubyzip.gemspec +3 -3
- data/samples/gtk_ruby_zip.rb +1 -1
- data/samples/qtzip.rb +1 -1
- metadata +14 -12
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Zip
|
|
4
|
+
# Info-ZIP Extra for AES encryption
|
|
5
|
+
class ExtraField::AES < ExtraField::Generic # :nodoc:
|
|
6
|
+
attr_reader :vendor_version, :vendor_id, :encryption_strength, :compression_method
|
|
7
|
+
|
|
8
|
+
HEADER_ID = [0x9901].pack('v')
|
|
9
|
+
register_map
|
|
10
|
+
|
|
11
|
+
def initialize(binstr = nil)
|
|
12
|
+
@vendor_version = nil
|
|
13
|
+
@vendor_id = nil
|
|
14
|
+
@encryption_strength = nil
|
|
15
|
+
@compression_method = nil
|
|
16
|
+
binstr && merge(binstr)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ==(other)
|
|
20
|
+
@vendor_version == other.vendor_version &&
|
|
21
|
+
@vendor_id == other.vendor_id &&
|
|
22
|
+
@encryption_strength == other.encryption_strength &&
|
|
23
|
+
@compression_method == other.compression_method
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def merge(binstr)
|
|
27
|
+
return if binstr.empty?
|
|
28
|
+
|
|
29
|
+
size, content = initial_parse(binstr)
|
|
30
|
+
(size && content) || return
|
|
31
|
+
|
|
32
|
+
@vendor_version, @vendor_id,
|
|
33
|
+
@encryption_strength, @compression_method = content.unpack('va2Cv')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# We can never suppress the AES extra field as it is needed to read the file.
|
|
37
|
+
def suppress?
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def pack_for_local
|
|
42
|
+
[@vendor_version, @vendor_id,
|
|
43
|
+
@encryption_strength, @compression_method].pack('va2Cv')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def pack_for_c_dir
|
|
47
|
+
pack_for_local
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -9,7 +9,7 @@ module Zip
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def self.name
|
|
12
|
-
@name ||= to_s.split('::')
|
|
12
|
+
@name ||= to_s.split('::').last.downcase.to_sym
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# return field [size, content] or false
|
|
@@ -24,6 +24,12 @@ module Zip
|
|
|
24
24
|
[binstr[2, 2].unpack1('v'), binstr[4..]]
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# Default strategy is to suppress all extra fields if we're asked to.
|
|
28
|
+
# Specific extra field types can override this if they need to be kept.
|
|
29
|
+
def suppress?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
27
33
|
def to_local_bin
|
|
28
34
|
s = pack_for_local
|
|
29
35
|
(self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v')) << s
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'generic'
|
|
4
|
+
|
|
3
5
|
module Zip
|
|
4
6
|
# A class to hold unknown extra fields so that they are preserved.
|
|
5
|
-
class ExtraField::Unknown # :nodoc:
|
|
7
|
+
class ExtraField::Unknown < ExtraField::Generic # :nodoc:
|
|
6
8
|
def initialize
|
|
7
9
|
@local_bin = +''
|
|
8
10
|
@cdir_bin = +''
|
|
@@ -56,6 +56,13 @@ module Zip
|
|
|
56
56
|
end
|
|
57
57
|
private :extract
|
|
58
58
|
|
|
59
|
+
# We can suppress the zip64 extra field unless we know the size is large or
|
|
60
|
+
# the relative header offset is large (for central directory entries).
|
|
61
|
+
def suppress?
|
|
62
|
+
!(@original_size && @original_size >= 0xFFFFFFFF) ||
|
|
63
|
+
(@relative_header_offset && @relative_header_offset >= 0xFFFFFFFF)
|
|
64
|
+
end
|
|
65
|
+
|
|
59
66
|
def pack_for_local
|
|
60
67
|
# Local header entries must contain original size and compressed size;
|
|
61
68
|
# other fields do not apply.
|
data/lib/zip/extra_field.rb
CHANGED
|
@@ -19,14 +19,14 @@ module Zip
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def extra_field_type_unknown(binstr, len, index, local)
|
|
22
|
-
self[
|
|
22
|
+
self[:unknown] ||= Unknown.new
|
|
23
23
|
|
|
24
24
|
if !len || len + 4 > binstr[index..].bytesize
|
|
25
|
-
self[
|
|
25
|
+
self[:unknown].merge(binstr[index..], local: local)
|
|
26
26
|
return
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
self[
|
|
29
|
+
self[:unknown].merge(binstr[index, len + 4], local: local)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def merge(binstr, local: false)
|
|
@@ -57,10 +57,17 @@ module Zip
|
|
|
57
57
|
# signature/size does not prevent known fields from being read back in.
|
|
58
58
|
def ordered_values
|
|
59
59
|
result = []
|
|
60
|
-
each { |k, v| k ==
|
|
60
|
+
each { |k, v| k == :unknown ? result.push(v) : result.unshift(v) }
|
|
61
61
|
result
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# Remove any extra fields that indicate they can be safely suppressed.
|
|
65
|
+
def suppress_fields!(fields)
|
|
66
|
+
reject! do |k, v|
|
|
67
|
+
v.suppress? if fields == true || [*fields].include?(k)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
64
71
|
def to_local_bin
|
|
65
72
|
ordered_values.map! { |v| v.to_local_bin.force_encoding('BINARY') }.join
|
|
66
73
|
end
|
|
@@ -91,6 +98,7 @@ require 'zip/extra_field/old_unix'
|
|
|
91
98
|
require 'zip/extra_field/unix'
|
|
92
99
|
require 'zip/extra_field/zip64'
|
|
93
100
|
require 'zip/extra_field/ntfs'
|
|
101
|
+
require 'zip/extra_field/aes'
|
|
94
102
|
|
|
95
103
|
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
96
104
|
# rubyzip is free software; you can redistribute it and/or
|
data/lib/zip/file.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'fileutils'
|
|
3
4
|
require 'forwardable'
|
|
4
5
|
|
|
5
6
|
require_relative 'file_split'
|
|
@@ -75,7 +76,8 @@ module Zip
|
|
|
75
76
|
restore_ownership: DEFAULT_RESTORE_OPTIONS[:restore_ownership],
|
|
76
77
|
restore_permissions: DEFAULT_RESTORE_OPTIONS[:restore_permissions],
|
|
77
78
|
restore_times: DEFAULT_RESTORE_OPTIONS[:restore_times],
|
|
78
|
-
compression_level: ::Zip.default_compression
|
|
79
|
+
compression_level: ::Zip.default_compression,
|
|
80
|
+
suppress_extra_fields: false)
|
|
79
81
|
super()
|
|
80
82
|
|
|
81
83
|
@name = path_or_io.respond_to?(:path) ? path_or_io.path : path_or_io
|
|
@@ -83,10 +85,11 @@ module Zip
|
|
|
83
85
|
|
|
84
86
|
initialize_cdir(path_or_io, buffer: buffer)
|
|
85
87
|
|
|
86
|
-
@restore_ownership
|
|
87
|
-
@restore_permissions
|
|
88
|
-
@restore_times
|
|
89
|
-
@compression_level
|
|
88
|
+
@restore_ownership = restore_ownership
|
|
89
|
+
@restore_permissions = restore_permissions
|
|
90
|
+
@restore_times = restore_times
|
|
91
|
+
@compression_level = compression_level
|
|
92
|
+
@suppress_extra_fields = suppress_extra_fields
|
|
90
93
|
end
|
|
91
94
|
|
|
92
95
|
class << self
|
|
@@ -97,13 +100,14 @@ module Zip
|
|
|
97
100
|
restore_ownership: DEFAULT_RESTORE_OPTIONS[:restore_ownership],
|
|
98
101
|
restore_permissions: DEFAULT_RESTORE_OPTIONS[:restore_permissions],
|
|
99
102
|
restore_times: DEFAULT_RESTORE_OPTIONS[:restore_times],
|
|
100
|
-
compression_level: ::Zip.default_compression
|
|
101
|
-
|
|
102
|
-
zf = ::Zip::File.new(file_name, create:
|
|
103
|
-
restore_ownership:
|
|
104
|
-
restore_permissions:
|
|
105
|
-
restore_times:
|
|
106
|
-
compression_level:
|
|
103
|
+
compression_level: ::Zip.default_compression,
|
|
104
|
+
suppress_extra_fields: false)
|
|
105
|
+
zf = ::Zip::File.new(file_name, create: create,
|
|
106
|
+
restore_ownership: restore_ownership,
|
|
107
|
+
restore_permissions: restore_permissions,
|
|
108
|
+
restore_times: restore_times,
|
|
109
|
+
compression_level: compression_level,
|
|
110
|
+
suppress_extra_fields: suppress_extra_fields)
|
|
107
111
|
|
|
108
112
|
return zf unless block_given?
|
|
109
113
|
|
|
@@ -122,8 +126,8 @@ module Zip
|
|
|
122
126
|
restore_ownership: DEFAULT_RESTORE_OPTIONS[:restore_ownership],
|
|
123
127
|
restore_permissions: DEFAULT_RESTORE_OPTIONS[:restore_permissions],
|
|
124
128
|
restore_times: DEFAULT_RESTORE_OPTIONS[:restore_times],
|
|
125
|
-
compression_level: ::Zip.default_compression
|
|
126
|
-
|
|
129
|
+
compression_level: ::Zip.default_compression,
|
|
130
|
+
suppress_extra_fields: false)
|
|
127
131
|
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.kind_of?(String)
|
|
128
132
|
raise 'Zip::File.open_buffer expects a String or IO-like argument' \
|
|
129
133
|
"(responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
|
@@ -132,10 +136,11 @@ module Zip
|
|
|
132
136
|
io = ::StringIO.new(io) if io.kind_of?(::String)
|
|
133
137
|
|
|
134
138
|
zf = ::Zip::File.new(io, create: create, buffer: true,
|
|
135
|
-
restore_ownership:
|
|
136
|
-
restore_permissions:
|
|
137
|
-
restore_times:
|
|
138
|
-
compression_level:
|
|
139
|
+
restore_ownership: restore_ownership,
|
|
140
|
+
restore_permissions: restore_permissions,
|
|
141
|
+
restore_times: restore_times,
|
|
142
|
+
compression_level: compression_level,
|
|
143
|
+
suppress_extra_fields: suppress_extra_fields)
|
|
139
144
|
|
|
140
145
|
return zf unless block_given?
|
|
141
146
|
|
|
@@ -191,7 +196,6 @@ module Zip
|
|
|
191
196
|
extra: nil, compressed_size: nil, crc: nil,
|
|
192
197
|
compression_method: nil, compression_level: nil,
|
|
193
198
|
size: nil, time: nil, &a_proc)
|
|
194
|
-
|
|
195
199
|
new_entry =
|
|
196
200
|
if entry.kind_of?(Entry)
|
|
197
201
|
entry
|
|
@@ -288,7 +292,7 @@ module Zip
|
|
|
288
292
|
return if name.kind_of?(StringIO) || !commit_required?
|
|
289
293
|
|
|
290
294
|
on_success_replace do |tmp_file|
|
|
291
|
-
::Zip::OutputStream.open(tmp_file) do |zos|
|
|
295
|
+
::Zip::OutputStream.open(tmp_file, suppress_extra_fields: @suppress_extra_fields) do |zos|
|
|
292
296
|
@cdir.each do |e|
|
|
293
297
|
e.write_to_zip_output_stream(zos)
|
|
294
298
|
e.clean_up
|
|
@@ -304,7 +308,7 @@ module Zip
|
|
|
304
308
|
def write_buffer(io = ::StringIO.new)
|
|
305
309
|
return io unless commit_required?
|
|
306
310
|
|
|
307
|
-
::Zip::OutputStream.write_buffer(io) do |zos|
|
|
311
|
+
::Zip::OutputStream.write_buffer(io, suppress_extra_fields: @suppress_extra_fields) do |zos|
|
|
308
312
|
@cdir.each { |e| e.write_to_zip_output_stream(zos) }
|
|
309
313
|
zos.comment = comment
|
|
310
314
|
end
|
|
@@ -412,7 +416,7 @@ module Zip
|
|
|
412
416
|
::File.chmod(@file_permissions, name) unless @create
|
|
413
417
|
end
|
|
414
418
|
ensure
|
|
415
|
-
|
|
419
|
+
FileUtils.rm_f(tmp_filename)
|
|
416
420
|
end
|
|
417
421
|
end
|
|
418
422
|
end
|
data/lib/zip/filesystem/file.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Zip
|
|
|
27
27
|
|
|
28
28
|
def unix_mode_cmp(filename, mode)
|
|
29
29
|
e = find_entry(filename)
|
|
30
|
-
e.fstype == FSTYPE_UNIX && (
|
|
30
|
+
e.fstype == FSTYPE_UNIX && (e.external_file_attributes >> 16).anybits?(mode)
|
|
31
31
|
rescue Errno::ENOENT
|
|
32
32
|
false
|
|
33
33
|
end
|
|
@@ -102,18 +102,19 @@ module Zip
|
|
|
102
102
|
@mapped_zip.get_entry(filename).size
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
# Returns nil for not found and nil for directories
|
|
105
|
+
# Returns nil for not found and nil for directories.
|
|
106
|
+
# We disable the cop here for compatibility with `::File.size?`.
|
|
106
107
|
def size?(filename)
|
|
107
108
|
entry = @mapped_zip.find_entry(filename)
|
|
108
|
-
entry.nil? || entry.directory? ? nil : entry.size
|
|
109
|
+
entry.nil? || entry.directory? ? nil : entry.size # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
|
|
109
110
|
end
|
|
110
111
|
|
|
111
112
|
def chown(owner, group, *filenames)
|
|
112
113
|
filenames.each do |filename|
|
|
113
114
|
e = find_entry(filename)
|
|
114
|
-
e.extra.create(
|
|
115
|
-
e.extra[
|
|
116
|
-
e.extra[
|
|
115
|
+
e.extra.create(:iunix) unless e.extra.member?(:iunix)
|
|
116
|
+
e.extra[:iunix].uid = owner
|
|
117
|
+
e.extra[:iunix].gid = group
|
|
117
118
|
end
|
|
118
119
|
filenames.size
|
|
119
120
|
end
|
|
@@ -36,8 +36,8 @@ module Zip
|
|
|
36
36
|
|
|
37
37
|
def gid
|
|
38
38
|
e = find_entry
|
|
39
|
-
if e.extra.member?
|
|
40
|
-
e.extra[
|
|
39
|
+
if e.extra.member? :iunix
|
|
40
|
+
e.extra[:iunix].gid || 0
|
|
41
41
|
else
|
|
42
42
|
0
|
|
43
43
|
end
|
|
@@ -45,8 +45,8 @@ module Zip
|
|
|
45
45
|
|
|
46
46
|
def uid
|
|
47
47
|
e = find_entry
|
|
48
|
-
if e.extra.member?
|
|
49
|
-
e.extra[
|
|
48
|
+
if e.extra.member? :iunix
|
|
49
|
+
e.extra[:iunix].uid || 0
|
|
50
50
|
else
|
|
51
51
|
0
|
|
52
52
|
end
|
data/lib/zip/inflater.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Zip
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def read(length = nil, outbuf = +'')
|
|
13
|
-
return (length.nil? || length.zero? ? '' : nil) if eof
|
|
13
|
+
return (length.nil? || length.zero? ? '' : nil) if eof?
|
|
14
14
|
|
|
15
15
|
while length.nil? || (@buffer.bytesize < length)
|
|
16
16
|
break if input_finished?
|
|
@@ -21,11 +21,12 @@ module Zip
|
|
|
21
21
|
outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def eof
|
|
24
|
+
def eof?
|
|
25
25
|
@buffer.empty? && input_finished?
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
# Alias for compatibility. Remove for version 4.
|
|
29
|
+
alias eof eof?
|
|
29
30
|
|
|
30
31
|
private
|
|
31
32
|
|
data/lib/zip/input_stream.rb
CHANGED
|
@@ -55,7 +55,7 @@ module Zip
|
|
|
55
55
|
super()
|
|
56
56
|
@archive_io = get_io(context, offset)
|
|
57
57
|
@decompressor = ::Zip::NullDecompressor
|
|
58
|
-
@decrypter = decrypter
|
|
58
|
+
@decrypter = decrypter
|
|
59
59
|
@current_entry = nil
|
|
60
60
|
@complete_entry = nil
|
|
61
61
|
end
|
|
@@ -135,29 +135,48 @@ module Zip
|
|
|
135
135
|
@current_entry = ::Zip::Entry.read_local_entry(@archive_io)
|
|
136
136
|
return if @current_entry.nil?
|
|
137
137
|
|
|
138
|
-
if @current_entry.encrypted? && @decrypter.kind_of?(NullDecrypter)
|
|
139
|
-
raise Error,
|
|
140
|
-
'A password is required to decode this zip file'
|
|
141
|
-
end
|
|
142
|
-
|
|
143
138
|
if @current_entry.incomplete? && @current_entry.compressed_size == 0 && !@complete_entry
|
|
144
139
|
raise StreamingError, @current_entry
|
|
145
140
|
end
|
|
146
141
|
|
|
147
|
-
@
|
|
148
|
-
@decompressor = get_decompressor
|
|
142
|
+
@decompressor = assemble_io
|
|
149
143
|
flush
|
|
150
144
|
@current_entry
|
|
151
145
|
end
|
|
152
146
|
|
|
147
|
+
def assemble_io # :nodoc:
|
|
148
|
+
io = if @current_entry.encrypted?
|
|
149
|
+
raise Error, 'A password is required to decode this zip file.' if @decrypter.nil?
|
|
150
|
+
|
|
151
|
+
get_decrypted_io
|
|
152
|
+
else
|
|
153
|
+
@archive_io
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
get_decompressor(io)
|
|
157
|
+
end
|
|
158
|
+
|
|
153
159
|
def get_decrypted_io # :nodoc:
|
|
154
160
|
header = @archive_io.read(@decrypter.header_bytesize)
|
|
155
161
|
@decrypter.reset!(header)
|
|
156
162
|
|
|
157
|
-
|
|
163
|
+
compressed_size =
|
|
164
|
+
if @current_entry.incomplete? && @current_entry.crc == 0 &&
|
|
165
|
+
@current_entry.compressed_size == 0 && @complete_entry
|
|
166
|
+
@complete_entry.compressed_size
|
|
167
|
+
else
|
|
168
|
+
@current_entry.compressed_size
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
if @decrypter.kind_of?(::Zip::AESDecrypter)
|
|
172
|
+
compressed_size -= @decrypter.header_bytesize
|
|
173
|
+
compressed_size -= ::Zip::AESEncryption::AUTHENTICATION_CODE_LENGTH
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
::Zip::DecryptedIo.new(@archive_io, @decrypter, compressed_size)
|
|
158
177
|
end
|
|
159
178
|
|
|
160
|
-
def get_decompressor # :nodoc:
|
|
179
|
+
def get_decompressor(io) # :nodoc:
|
|
161
180
|
return ::Zip::NullDecompressor if @current_entry.nil?
|
|
162
181
|
|
|
163
182
|
decompressed_size =
|
|
@@ -175,7 +194,7 @@ module Zip
|
|
|
175
194
|
raise ::Zip::CompressionMethodError, @current_entry.compression_method
|
|
176
195
|
end
|
|
177
196
|
|
|
178
|
-
decompressor_class.new(
|
|
197
|
+
decompressor_class.new(io, decompressed_size)
|
|
179
198
|
end
|
|
180
199
|
|
|
181
200
|
def produce_input # :nodoc:
|
|
@@ -183,7 +202,7 @@ module Zip
|
|
|
183
202
|
end
|
|
184
203
|
|
|
185
204
|
def input_finished? # :nodoc:
|
|
186
|
-
@decompressor.eof
|
|
205
|
+
@decompressor.eof?
|
|
187
206
|
end
|
|
188
207
|
end
|
|
189
208
|
end
|
|
@@ -117,11 +117,12 @@ module Zip
|
|
|
117
117
|
|
|
118
118
|
alias each each_line
|
|
119
119
|
|
|
120
|
-
def eof
|
|
120
|
+
def eof?
|
|
121
121
|
@output_buffer.empty? && input_finished?
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
# Alias for compatibility. Remove for version 4.
|
|
125
|
+
alias eof eof?
|
|
125
126
|
end
|
|
126
127
|
end
|
|
127
128
|
end
|
data/lib/zip/output_stream.rb
CHANGED
|
@@ -29,7 +29,7 @@ module Zip
|
|
|
29
29
|
|
|
30
30
|
# Opens the indicated zip file. If a file with that name already
|
|
31
31
|
# exists it will be overwritten.
|
|
32
|
-
def initialize(file_name, stream: false, encrypter: nil)
|
|
32
|
+
def initialize(file_name, stream: false, encrypter: nil, suppress_extra_fields: false)
|
|
33
33
|
super()
|
|
34
34
|
@file_name = file_name
|
|
35
35
|
@output_stream = if stream
|
|
@@ -43,6 +43,7 @@ module Zip
|
|
|
43
43
|
@cdir = ::Zip::CentralDirectory.new
|
|
44
44
|
@compressor = ::Zip::NullCompressor.instance
|
|
45
45
|
@encrypter = encrypter || ::Zip::NullEncrypter.new
|
|
46
|
+
@suppress_extra_fields = suppress_extra_fields
|
|
46
47
|
@closed = false
|
|
47
48
|
@current_entry = nil
|
|
48
49
|
end
|
|
@@ -51,19 +52,21 @@ module Zip
|
|
|
51
52
|
# Same as #initialize but if a block is passed the opened
|
|
52
53
|
# stream is passed to the block and closed when the block
|
|
53
54
|
# returns.
|
|
54
|
-
def open(file_name, encrypter: nil)
|
|
55
|
+
def open(file_name, encrypter: nil, suppress_extra_fields: false)
|
|
55
56
|
return new(file_name) unless block_given?
|
|
56
57
|
|
|
57
|
-
zos = new(file_name, stream: false, encrypter: encrypter
|
|
58
|
+
zos = new(file_name, stream: false, encrypter: encrypter,
|
|
59
|
+
suppress_extra_fields: suppress_extra_fields)
|
|
58
60
|
yield zos
|
|
59
61
|
ensure
|
|
60
62
|
zos.close if zos
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
# Same as #open but writes to a filestream instead
|
|
64
|
-
def write_buffer(io = ::StringIO.new, encrypter: nil)
|
|
66
|
+
def write_buffer(io = ::StringIO.new, encrypter: nil, suppress_extra_fields: false)
|
|
65
67
|
io.binmode if io.respond_to?(:binmode)
|
|
66
|
-
zos = new(io, stream: true, encrypter: encrypter
|
|
68
|
+
zos = new(io, stream: true, encrypter: encrypter,
|
|
69
|
+
suppress_extra_fields: suppress_extra_fields)
|
|
67
70
|
yield zos
|
|
68
71
|
zos.close_buffer
|
|
69
72
|
end
|
|
@@ -75,7 +78,7 @@ module Zip
|
|
|
75
78
|
|
|
76
79
|
finalize_current_entry
|
|
77
80
|
update_local_headers
|
|
78
|
-
@cdir.write_to_stream(@output_stream)
|
|
81
|
+
@cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
79
82
|
@output_stream.close
|
|
80
83
|
@closed = true
|
|
81
84
|
end
|
|
@@ -86,7 +89,7 @@ module Zip
|
|
|
86
89
|
|
|
87
90
|
finalize_current_entry
|
|
88
91
|
update_local_headers
|
|
89
|
-
@cdir.write_to_stream(@output_stream)
|
|
92
|
+
@cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
90
93
|
@closed = true
|
|
91
94
|
@output_stream.flush
|
|
92
95
|
@output_stream
|
|
@@ -157,7 +160,7 @@ module Zip
|
|
|
157
160
|
def init_next_entry(entry)
|
|
158
161
|
finalize_current_entry
|
|
159
162
|
@cdir << entry
|
|
160
|
-
entry.write_local_entry(@output_stream)
|
|
163
|
+
entry.write_local_entry(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
161
164
|
@encrypter.reset!
|
|
162
165
|
@output_stream << @encrypter.header(entry.mtime)
|
|
163
166
|
@compressor = get_compressor(entry)
|
|
@@ -178,7 +181,8 @@ module Zip
|
|
|
178
181
|
pos = @output_stream.pos
|
|
179
182
|
@cdir.each do |entry|
|
|
180
183
|
@output_stream.pos = entry.local_header_offset
|
|
181
|
-
entry.write_local_entry(@output_stream,
|
|
184
|
+
entry.write_local_entry(@output_stream, suppress_extra_fields: @suppress_extra_fields,
|
|
185
|
+
rewrite: true)
|
|
182
186
|
end
|
|
183
187
|
@output_stream.pos = pos
|
|
184
188
|
end
|
|
@@ -8,7 +8,7 @@ module Zip
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def read(length = nil, outbuf = +'')
|
|
11
|
-
return (length.nil? || length.zero? ? '' : nil) if eof
|
|
11
|
+
return (length.nil? || length.zero? ? '' : nil) if eof?
|
|
12
12
|
|
|
13
13
|
if length.nil? || (@read_so_far + length) > decompressed_size
|
|
14
14
|
length = decompressed_size - @read_so_far
|
|
@@ -18,11 +18,12 @@ module Zip
|
|
|
18
18
|
input_stream.read(length, outbuf)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def eof
|
|
21
|
+
def eof?
|
|
22
22
|
@read_so_far >= decompressed_size
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
# Alias for compatibility. Remove for version 4.
|
|
26
|
+
alias eof eof?
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
|
data/lib/zip/version.rb
CHANGED
data/lib/zip.rb
CHANGED
|
@@ -30,6 +30,7 @@ require 'zip/crypto/decrypted_io'
|
|
|
30
30
|
require 'zip/crypto/encryption'
|
|
31
31
|
require 'zip/crypto/null_encryption'
|
|
32
32
|
require 'zip/crypto/traditional_encryption'
|
|
33
|
+
require 'zip/crypto/aes_encryption'
|
|
33
34
|
require 'zip/inflater'
|
|
34
35
|
require 'zip/deflater'
|
|
35
36
|
require 'zip/streamable_stream'
|
|
@@ -43,6 +44,7 @@ require 'zip/errors'
|
|
|
43
44
|
# ::Dir APIs then `require 'zip/filesystem'` and see FileSystem.
|
|
44
45
|
module Zip
|
|
45
46
|
extend self
|
|
47
|
+
|
|
46
48
|
attr_accessor :unicode_names,
|
|
47
49
|
:on_exists_proc,
|
|
48
50
|
:continue_on_exists_proc,
|
data/rubyzip.gemspec
CHANGED
|
@@ -31,9 +31,9 @@ Gem::Specification.new do |s|
|
|
|
31
31
|
s.add_development_dependency 'minitest', '~> 5.25'
|
|
32
32
|
s.add_development_dependency 'rake', '~> 13.2'
|
|
33
33
|
s.add_development_dependency 'rdoc', '~> 6.11'
|
|
34
|
-
s.add_development_dependency 'rubocop', '~> 1.
|
|
35
|
-
s.add_development_dependency 'rubocop-performance', '~> 1.
|
|
36
|
-
s.add_development_dependency 'rubocop-rake', '~> 0.
|
|
34
|
+
s.add_development_dependency 'rubocop', '~> 1.80.2'
|
|
35
|
+
s.add_development_dependency 'rubocop-performance', '~> 1.26.0'
|
|
36
|
+
s.add_development_dependency 'rubocop-rake', '~> 0.7.1'
|
|
37
37
|
s.add_development_dependency 'simplecov', '~> 0.22.0'
|
|
38
38
|
s.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
|
39
39
|
end
|
data/samples/gtk_ruby_zip.rb
CHANGED
data/samples/qtzip.rb
CHANGED