rubyzip 2.4.1 → 3.7.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 +549 -0
- data/LICENSE.md +24 -0
- data/README.md +250 -44
- data/Rakefile +15 -13
- data/lib/rubyzip.rb +3 -0
- data/lib/zip/central_directory.rb +194 -125
- data/lib/zip/compressor.rb +3 -1
- data/lib/zip/constants.rb +30 -21
- data/lib/zip/crypto/aes_encryption.rb +213 -0
- data/lib/zip/crypto/decrypted_io.rb +27 -15
- data/lib/zip/crypto/encryption.rb +13 -2
- data/lib/zip/crypto/null_encryption.rb +5 -13
- data/lib/zip/crypto/traditional_encryption.rb +13 -7
- data/lib/zip/decompressor.rb +4 -3
- data/lib/zip/deflater.rb +12 -8
- data/lib/zip/dirtyable.rb +32 -0
- data/lib/zip/dos_time.rb +64 -6
- data/lib/zip/entry.rb +432 -270
- data/lib/zip/entry_set.rb +11 -9
- data/lib/zip/errors.rb +152 -16
- data/lib/zip/extra_field/aes.rb +50 -0
- data/lib/zip/extra_field/generic.rb +10 -11
- data/lib/zip/extra_field/ntfs.rb +6 -4
- data/lib/zip/extra_field/old_unix.rb +5 -3
- data/lib/zip/extra_field/universal_time.rb +3 -1
- data/lib/zip/extra_field/unix.rb +7 -5
- data/lib/zip/extra_field/unknown.rb +35 -0
- data/lib/zip/extra_field/zip64.rb +19 -5
- data/lib/zip/extra_field.rb +25 -23
- data/lib/zip/file.rb +261 -262
- data/lib/zip/file_split.rb +91 -0
- data/lib/zip/filesystem/dir.rb +86 -0
- data/lib/zip/filesystem/directory_iterator.rb +48 -0
- data/lib/zip/filesystem/file.rb +263 -0
- data/lib/zip/filesystem/file_stat.rb +110 -0
- data/lib/zip/filesystem/zip_file_name_mapper.rb +81 -0
- data/lib/zip/filesystem.rb +27 -596
- data/lib/zip/inflater.rb +13 -10
- data/lib/zip/input_stream.rb +102 -61
- data/lib/zip/ioextras/abstract_input_stream.rb +156 -58
- data/lib/zip/ioextras/abstract_output_stream.rb +15 -3
- data/lib/zip/ioextras/fake_io.rb +39 -0
- data/lib/zip/ioextras.rb +12 -16
- data/lib/zip/null_compressor.rb +3 -1
- data/lib/zip/null_decompressor.rb +6 -3
- data/lib/zip/null_input_stream.rb +3 -1
- data/lib/zip/output_stream.rb +76 -64
- data/lib/zip/pass_thru_compressor.rb +6 -3
- data/lib/zip/pass_thru_decompressor.rb +12 -9
- data/lib/zip/streamable_directory.rb +3 -1
- data/lib/zip/streamable_stream.rb +4 -1
- data/lib/zip/version.rb +4 -1
- data/lib/zip.rb +28 -23
- data/rubyzip.gemspec +39 -0
- data/samples/example.rb +8 -3
- data/samples/example_filesystem.rb +3 -2
- data/samples/example_recursive.rb +3 -1
- data/samples/gtk_ruby_zip.rb +5 -3
- data/samples/qtzip.rb +7 -6
- data/samples/write_simple.rb +2 -1
- data/samples/zipfind.rb +1 -0
- metadata +88 -52
- data/TODO +0 -15
- data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
module NullDecompressor
|
|
4
|
+
module NullDecompressor # :nodoc:all
|
|
3
5
|
module_function
|
|
4
6
|
|
|
5
7
|
def read(_length = nil, _outbuf = nil)
|
|
6
8
|
nil
|
|
7
9
|
end
|
|
8
10
|
|
|
9
|
-
def eof
|
|
11
|
+
def eof?
|
|
10
12
|
true
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
# Alias for compatibility. Remove for version 4.
|
|
16
|
+
alias eof eof?
|
|
14
17
|
end
|
|
15
18
|
end
|
|
16
19
|
|
data/lib/zip/output_stream.rb
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
##
|
|
1
6
|
module Zip
|
|
2
7
|
# ZipOutputStream is the basic class for writing zip files. It is
|
|
3
8
|
# possible to create a ZipOutputStream object directly, passing
|
|
@@ -16,57 +21,59 @@ module Zip
|
|
|
16
21
|
#
|
|
17
22
|
# java.util.zip.ZipOutputStream is the original inspiration for this
|
|
18
23
|
# class.
|
|
19
|
-
|
|
20
24
|
class OutputStream
|
|
25
|
+
extend Forwardable
|
|
21
26
|
include ::Zip::IOExtras::AbstractOutputStream
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
def_delegators :@cdir, :comment, :comment=
|
|
24
29
|
|
|
25
30
|
# Opens the indicated zip file. If a file with that name already
|
|
26
31
|
# exists it will be overwritten.
|
|
27
|
-
def initialize(file_name,
|
|
28
|
-
super()
|
|
29
|
-
|
|
30
|
-
Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
|
|
31
|
-
|
|
32
|
+
def initialize(file_name, stream: false, encrypter: nil, suppress_extra_fields: false, **opts)
|
|
33
|
+
super(**opts)
|
|
32
34
|
@file_name = file_name
|
|
33
|
-
@output_stream = if stream
|
|
34
|
-
iostream = @file_name.dup
|
|
35
|
+
@output_stream = if stream
|
|
36
|
+
iostream = Zip::RUNNING_ON_WINDOWS ? @file_name : @file_name.dup
|
|
35
37
|
iostream.reopen(@file_name)
|
|
36
38
|
iostream.rewind
|
|
37
39
|
iostream
|
|
38
40
|
else
|
|
39
41
|
::File.new(@file_name, 'wb')
|
|
40
42
|
end
|
|
41
|
-
@
|
|
43
|
+
@cdir = ::Zip::CentralDirectory.new
|
|
42
44
|
@compressor = ::Zip::NullCompressor.instance
|
|
43
|
-
@encrypter = encrypter ||
|
|
45
|
+
@encrypter = encrypter || ::Zip::NullEncrypter.new
|
|
46
|
+
@suppress_extra_fields = suppress_extra_fields
|
|
44
47
|
@closed = false
|
|
45
48
|
@current_entry = nil
|
|
46
|
-
@comment = nil
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
# Same as #initialize but if a block is passed the opened
|
|
50
|
-
# stream is passed to the block and closed when the block
|
|
51
|
-
# returns.
|
|
52
51
|
class << self
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
# Same as #initialize but if a block is passed the opened
|
|
53
|
+
# stream is passed to the block and closed when the block
|
|
54
|
+
# returns.
|
|
55
|
+
def open(file_name, encrypter: nil, suppress_extra_fields: false, **opts)
|
|
56
|
+
unless block_given?
|
|
57
|
+
return new(
|
|
58
|
+
file_name,
|
|
59
|
+
encrypter: encrypter,
|
|
60
|
+
suppress_extra_fields: suppress_extra_fields,
|
|
61
|
+
**opts
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
zos = new(file_name, stream: false, encrypter: encrypter,
|
|
66
|
+
suppress_extra_fields: suppress_extra_fields, **opts)
|
|
59
67
|
yield zos
|
|
60
68
|
ensure
|
|
61
69
|
zos.close if zos
|
|
62
70
|
end
|
|
63
71
|
|
|
64
72
|
# Same as #open but writes to a filestream instead
|
|
65
|
-
def write_buffer(io = ::StringIO.new,
|
|
66
|
-
Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil?
|
|
67
|
-
|
|
73
|
+
def write_buffer(io = ::StringIO.new, encrypter: nil, suppress_extra_fields: false, **opts)
|
|
68
74
|
io.binmode if io.respond_to?(:binmode)
|
|
69
|
-
zos = new(io, stream: true, encrypter:
|
|
75
|
+
zos = new(io, stream: true, encrypter: encrypter,
|
|
76
|
+
suppress_extra_fields: suppress_extra_fields, **opts)
|
|
70
77
|
yield zos
|
|
71
78
|
zos.close_buffer
|
|
72
79
|
end
|
|
@@ -78,7 +85,7 @@ module Zip
|
|
|
78
85
|
|
|
79
86
|
finalize_current_entry
|
|
80
87
|
update_local_headers
|
|
81
|
-
|
|
88
|
+
@cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
82
89
|
@output_stream.close
|
|
83
90
|
@closed = true
|
|
84
91
|
end
|
|
@@ -89,37 +96,41 @@ module Zip
|
|
|
89
96
|
|
|
90
97
|
finalize_current_entry
|
|
91
98
|
update_local_headers
|
|
92
|
-
|
|
99
|
+
@cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
93
100
|
@closed = true
|
|
101
|
+
@output_stream.flush
|
|
94
102
|
@output_stream
|
|
95
103
|
end
|
|
96
104
|
|
|
97
105
|
# Closes the current entry and opens a new for writing.
|
|
98
106
|
# +entry+ can be a ZipEntry object or a string.
|
|
99
|
-
def put_next_entry(
|
|
107
|
+
def put_next_entry(
|
|
108
|
+
entry_name, comment = '', extra = ExtraField.new,
|
|
109
|
+
compression_method = Entry::DEFLATED, level = Zip.default_compression
|
|
110
|
+
)
|
|
100
111
|
raise Error, 'zip stream is closed' if @closed
|
|
101
112
|
|
|
102
|
-
new_entry =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
init_next_entry(new_entry
|
|
113
|
+
new_entry =
|
|
114
|
+
if entry_name.kind_of?(Entry) || entry_name.kind_of?(StreamableStream)
|
|
115
|
+
entry_name
|
|
116
|
+
else
|
|
117
|
+
Entry.new(
|
|
118
|
+
@file_name, entry_name.to_s, comment: comment, extra: extra,
|
|
119
|
+
compression_method: compression_method, compression_level: level
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
init_next_entry(new_entry)
|
|
113
124
|
@current_entry = new_entry
|
|
114
125
|
end
|
|
115
126
|
|
|
116
|
-
def copy_raw_entry(entry)
|
|
127
|
+
def copy_raw_entry(entry) # :nodoc:
|
|
117
128
|
entry = entry.dup
|
|
118
129
|
raise Error, 'zip stream is closed' if @closed
|
|
119
130
|
raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
|
|
120
131
|
|
|
121
132
|
finalize_current_entry
|
|
122
|
-
@
|
|
133
|
+
@cdir << entry
|
|
123
134
|
src_pos = entry.local_header_offset
|
|
124
135
|
entry.write_local_entry(@output_stream)
|
|
125
136
|
@compressor = NullCompressor.instance
|
|
@@ -138,55 +149,56 @@ module Zip
|
|
|
138
149
|
return unless @current_entry
|
|
139
150
|
|
|
140
151
|
finish
|
|
141
|
-
@
|
|
142
|
-
|
|
152
|
+
@output_stream << @encrypter.trailer unless @current_entry.directory?
|
|
153
|
+
@current_entry.compressed_size = @output_stream.tell -
|
|
154
|
+
@current_entry.local_header_offset -
|
|
143
155
|
@current_entry.calculate_local_header_size
|
|
144
156
|
@current_entry.size = @compressor.size
|
|
145
|
-
@current_entry.crc = @compressor.crc
|
|
146
|
-
@output_stream << @encrypter.data_descriptor(
|
|
147
|
-
|
|
157
|
+
@current_entry.crc = @encrypter.crc(@compressor.crc)
|
|
158
|
+
@output_stream << @encrypter.data_descriptor(
|
|
159
|
+
@current_entry.crc,
|
|
160
|
+
@current_entry.compressed_size,
|
|
161
|
+
@current_entry.size
|
|
162
|
+
)
|
|
163
|
+
@current_entry.gp_flags |= @encrypter.gp_flags unless @current_entry.directory?
|
|
148
164
|
@current_entry = nil
|
|
149
165
|
@compressor = ::Zip::NullCompressor.instance
|
|
150
166
|
end
|
|
151
167
|
|
|
152
|
-
def init_next_entry(entry
|
|
168
|
+
def init_next_entry(entry)
|
|
153
169
|
finalize_current_entry
|
|
154
|
-
@
|
|
155
|
-
entry
|
|
170
|
+
@encrypter.prepare_entry(entry)
|
|
171
|
+
@cdir << entry
|
|
172
|
+
entry.write_local_entry(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
156
173
|
@encrypter.reset!
|
|
157
|
-
@output_stream << @encrypter.header(entry.mtime)
|
|
158
|
-
@compressor = get_compressor(entry
|
|
174
|
+
@output_stream << @encrypter.header(entry.mtime) unless entry.directory?
|
|
175
|
+
@compressor = get_compressor(entry)
|
|
159
176
|
end
|
|
160
177
|
|
|
161
|
-
def get_compressor(entry
|
|
178
|
+
def get_compressor(entry)
|
|
162
179
|
case entry.compression_method
|
|
163
180
|
when Entry::DEFLATED
|
|
164
|
-
::Zip::Deflater.new(@output_stream,
|
|
181
|
+
::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
|
|
165
182
|
when Entry::STORED
|
|
166
|
-
::Zip::PassThruCompressor.new(@output_stream)
|
|
183
|
+
::Zip::PassThruCompressor.new(@output_stream, @encrypter)
|
|
167
184
|
else
|
|
168
|
-
raise ::Zip::CompressionMethodError,
|
|
169
|
-
"Invalid compression method: '#{entry.compression_method}'"
|
|
185
|
+
raise ::Zip::CompressionMethodError, entry.compression_method
|
|
170
186
|
end
|
|
171
187
|
end
|
|
172
188
|
|
|
173
189
|
def update_local_headers
|
|
174
190
|
pos = @output_stream.pos
|
|
175
|
-
@
|
|
191
|
+
@cdir.each do |entry|
|
|
176
192
|
@output_stream.pos = entry.local_header_offset
|
|
177
|
-
entry.write_local_entry(@output_stream,
|
|
193
|
+
entry.write_local_entry(@output_stream, suppress_extra_fields: @suppress_extra_fields,
|
|
194
|
+
rewrite: true)
|
|
178
195
|
end
|
|
179
196
|
@output_stream.pos = pos
|
|
180
197
|
end
|
|
181
198
|
|
|
182
|
-
def write_central_directory
|
|
183
|
-
cdir = CentralDirectory.new(@entry_set, @comment)
|
|
184
|
-
cdir.write_to_stream(@output_stream)
|
|
185
|
-
end
|
|
186
|
-
|
|
187
199
|
protected
|
|
188
200
|
|
|
189
|
-
def finish
|
|
201
|
+
def finish # :nodoc:
|
|
190
202
|
@compressor.finish
|
|
191
203
|
end
|
|
192
204
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
class PassThruCompressor < Compressor
|
|
3
|
-
def initialize(output_stream)
|
|
4
|
+
class PassThruCompressor < Compressor # :nodoc:all
|
|
5
|
+
def initialize(output_stream, encrypter = NullEncrypter.new)
|
|
4
6
|
super()
|
|
5
7
|
@output_stream = output_stream
|
|
8
|
+
@encrypter = encrypter
|
|
6
9
|
@crc = Zlib.crc32
|
|
7
10
|
@size = 0
|
|
8
11
|
end
|
|
@@ -11,7 +14,7 @@ module Zip
|
|
|
11
14
|
val = data.to_s
|
|
12
15
|
@crc = Zlib.crc32(val, @crc)
|
|
13
16
|
@size += val.bytesize
|
|
14
|
-
@output_stream << val
|
|
17
|
+
@output_stream << @encrypter.encrypt(val)
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
attr_reader :size, :crc
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
class PassThruDecompressor < Decompressor
|
|
4
|
+
class PassThruDecompressor < Decompressor # :nodoc:all
|
|
3
5
|
def initialize(*args)
|
|
4
6
|
super
|
|
5
7
|
@read_so_far = 0
|
|
6
8
|
end
|
|
7
9
|
|
|
8
|
-
def read(
|
|
9
|
-
return (
|
|
10
|
+
def read(maxlen = nil)
|
|
11
|
+
return (maxlen.nil? || maxlen.zero? ? '' : nil) if eof?
|
|
10
12
|
|
|
11
|
-
if
|
|
12
|
-
|
|
13
|
+
if maxlen.nil? || (@read_so_far + maxlen) > decompressed_size
|
|
14
|
+
maxlen = decompressed_size - @read_so_far
|
|
13
15
|
end
|
|
14
16
|
|
|
15
|
-
@read_so_far +=
|
|
16
|
-
input_stream.read(
|
|
17
|
+
@read_so_far += maxlen
|
|
18
|
+
input_stream.read(maxlen)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
def eof
|
|
21
|
+
def eof?
|
|
20
22
|
@read_so_far >= decompressed_size
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
# Alias for compatibility. Remove for version 4.
|
|
26
|
+
alias eof eof?
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
4
|
class StreamableStream < DelegateClass(Entry) # :nodoc:all
|
|
3
5
|
def initialize(entry)
|
|
4
|
-
super
|
|
6
|
+
super
|
|
5
7
|
@temp_file = Tempfile.new(::File.basename(name))
|
|
6
8
|
@temp_file.binmode
|
|
7
9
|
end
|
|
@@ -42,6 +44,7 @@ module Zip
|
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
def clean_up
|
|
47
|
+
super
|
|
45
48
|
@temp_file.unlink
|
|
46
49
|
end
|
|
47
50
|
end
|
data/lib/zip/version.rb
CHANGED
data/lib/zip.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'English'
|
|
2
4
|
require 'delegate'
|
|
3
5
|
require 'singleton'
|
|
@@ -5,6 +7,7 @@ require 'tempfile'
|
|
|
5
7
|
require 'fileutils'
|
|
6
8
|
require 'stringio'
|
|
7
9
|
require 'zlib'
|
|
10
|
+
require 'zip/version'
|
|
8
11
|
require 'zip/constants'
|
|
9
12
|
require 'zip/dos_time'
|
|
10
13
|
require 'zip/ioextras'
|
|
@@ -27,33 +30,21 @@ require 'zip/crypto/decrypted_io'
|
|
|
27
30
|
require 'zip/crypto/encryption'
|
|
28
31
|
require 'zip/crypto/null_encryption'
|
|
29
32
|
require 'zip/crypto/traditional_encryption'
|
|
33
|
+
require 'zip/crypto/aes_encryption'
|
|
30
34
|
require 'zip/inflater'
|
|
31
35
|
require 'zip/deflater'
|
|
32
36
|
require 'zip/streamable_stream'
|
|
33
37
|
require 'zip/streamable_directory'
|
|
34
38
|
require 'zip/errors'
|
|
35
39
|
|
|
40
|
+
# Rubyzip is a ruby module for reading and writing zip files.
|
|
41
|
+
#
|
|
42
|
+
# The main entry points are File, InputStream and OutputStream. For a
|
|
43
|
+
# file/directory interface in the style of the standard ruby ::File and
|
|
44
|
+
# ::Dir APIs then `require 'zip/filesystem'` and see FileSystem.
|
|
36
45
|
module Zip
|
|
37
|
-
V3_API_WARNING_MSG = <<~END_MSG
|
|
38
|
-
You have called '%s' (from %s).
|
|
39
|
-
This method is changing or deprecated in version 3.0.0. Please see
|
|
40
|
-
https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x
|
|
41
|
-
for more information.
|
|
42
|
-
END_MSG
|
|
43
|
-
|
|
44
|
-
def self.warn_about_v3_api(method)
|
|
45
|
-
return unless ENV['RUBYZIP_V3_API_WARN']
|
|
46
|
-
|
|
47
|
-
loc = caller_locations(2, 1)[0]
|
|
48
|
-
from = "#{loc.path.split('/').last}:#{loc.lineno}"
|
|
49
|
-
warn format(V3_API_WARNING_MSG, method, from)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
if ENV['RUBYZIP_V3_API_WARN'] && RUBY_VERSION < '3.0'
|
|
53
|
-
warn 'RubyZip 3.0 will require Ruby 3.0 or later.'
|
|
54
|
-
end
|
|
55
|
-
|
|
56
46
|
extend self
|
|
47
|
+
|
|
57
48
|
attr_accessor :unicode_names,
|
|
58
49
|
:on_exists_proc,
|
|
59
50
|
:continue_on_exists_proc,
|
|
@@ -63,21 +54,35 @@ module Zip
|
|
|
63
54
|
:warn_invalid_date,
|
|
64
55
|
:case_insensitive_match,
|
|
65
56
|
:force_entry_names_encoding,
|
|
66
|
-
:validate_entry_sizes
|
|
57
|
+
:validate_entry_sizes,
|
|
58
|
+
:validate_declared_number_of_entries
|
|
59
|
+
|
|
60
|
+
DEFAULT_RESTORE_OPTIONS = {
|
|
61
|
+
restore_ownership: false,
|
|
62
|
+
restore_permissions: true,
|
|
63
|
+
restore_times: true
|
|
64
|
+
}.freeze # :nodoc:
|
|
65
|
+
|
|
66
|
+
# :nodoc:
|
|
67
|
+
# Remove this when JRuby#3962 is fixed.
|
|
68
|
+
ZLIB_FLUSHING_STRATEGY = defined?(JRUBY_VERSION) ? Zlib::SYNC_FLUSH : Zlib::NO_FLUSH
|
|
67
69
|
|
|
68
|
-
def reset!
|
|
70
|
+
def reset! # :nodoc:
|
|
69
71
|
@_ran_once = false
|
|
70
72
|
@unicode_names = false
|
|
71
73
|
@on_exists_proc = false
|
|
72
74
|
@continue_on_exists_proc = false
|
|
73
75
|
@sort_entries = false
|
|
74
|
-
@default_compression =
|
|
75
|
-
@write_zip64_support =
|
|
76
|
+
@default_compression = Zlib::DEFAULT_COMPRESSION
|
|
77
|
+
@write_zip64_support = true
|
|
76
78
|
@warn_invalid_date = true
|
|
77
79
|
@case_insensitive_match = false
|
|
80
|
+
@force_entry_names_encoding = nil
|
|
78
81
|
@validate_entry_sizes = true
|
|
82
|
+
@validate_declared_number_of_entries = false # Set this to `true` in v4.0.0?
|
|
79
83
|
end
|
|
80
84
|
|
|
85
|
+
# Set options for RubyZip in one block.
|
|
81
86
|
def setup
|
|
82
87
|
yield self unless @_ran_once
|
|
83
88
|
@_ran_once = true
|
data/rubyzip.gemspec
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/zip/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'rubyzip'
|
|
7
|
+
s.version = Zip::VERSION
|
|
8
|
+
s.authors = ['Robert Haines', 'John Lees-Miller', 'Alexander Simonov']
|
|
9
|
+
s.email = [
|
|
10
|
+
'hainesr@gmail.com', 'jdleesmiller@gmail.com', 'alex@simonov.me'
|
|
11
|
+
]
|
|
12
|
+
s.homepage = 'http://github.com/rubyzip/rubyzip'
|
|
13
|
+
s.platform = Gem::Platform::RUBY
|
|
14
|
+
s.summary = 'rubyzip is a ruby module for reading and writing zip files'
|
|
15
|
+
s.files = Dir.glob('{samples,lib}/**/*.rb') +
|
|
16
|
+
%w[LICENSE.md README.md Changelog.md Rakefile rubyzip.gemspec]
|
|
17
|
+
s.require_paths = ['lib']
|
|
18
|
+
s.license = 'BSD-2-Clause'
|
|
19
|
+
|
|
20
|
+
s.metadata = {
|
|
21
|
+
'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
|
|
22
|
+
'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
|
|
23
|
+
'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
|
|
24
|
+
'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
|
|
25
|
+
'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki',
|
|
26
|
+
'rubygems_mfa_required' => 'true'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
s.required_ruby_version = '>= 3.0'
|
|
30
|
+
|
|
31
|
+
s.add_development_dependency 'minitest', '~> 5.25'
|
|
32
|
+
s.add_development_dependency 'rake', '~> 13.2'
|
|
33
|
+
s.add_development_dependency 'rdoc', '~> 6.11'
|
|
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
|
+
s.add_development_dependency 'simplecov', '~> 0.22.0'
|
|
38
|
+
s.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
|
39
|
+
end
|
data/samples/example.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
$LOAD_PATH << '../lib'
|
|
4
5
|
system('zip example.zip example.rb gtk_ruby_zip.rb')
|
|
@@ -20,7 +21,8 @@ end
|
|
|
20
21
|
|
|
21
22
|
zf = Zip::File.new('example.zip')
|
|
22
23
|
zf.each_with_index do |entry, index|
|
|
23
|
-
puts "entry #{index} is #{entry.name}, size = #{entry.size},
|
|
24
|
+
puts "entry #{index} is #{entry.name}, size = #{entry.size}, " \
|
|
25
|
+
"compressed size = #{entry.compressed_size}"
|
|
24
26
|
# use zf.get_input_stream(entry) to get a ZipInputStream for the entry
|
|
25
27
|
# entry can be the ZipEntry object or any object which has a to_s method that
|
|
26
28
|
# returns the name of the entry.
|
|
@@ -70,8 +72,11 @@ part_zips_count = Zip::File.split('large_zip_file.zip', 2_097_152, false)
|
|
|
70
72
|
puts "Zip file splitted in #{part_zips_count} parts"
|
|
71
73
|
|
|
72
74
|
# Track splitting an archive
|
|
73
|
-
Zip::File.split(
|
|
74
|
-
|
|
75
|
+
Zip::File.split(
|
|
76
|
+
'large_zip_file.zip', 1_048_576, true, 'part_zip_file'
|
|
77
|
+
) do |part_count, part_index, chunk_bytes, segment_bytes|
|
|
78
|
+
puts "#{part_index} of #{part_count} part splitting: " \
|
|
79
|
+
"#{(chunk_bytes.to_f / segment_bytes * 100).to_i}%"
|
|
75
80
|
end
|
|
76
81
|
|
|
77
82
|
# For other examples, look at zip.rb and ziptest.rb
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
$LOAD_PATH << '../lib'
|
|
4
5
|
|
|
@@ -6,9 +7,9 @@ require 'zip/filesystem'
|
|
|
6
7
|
|
|
7
8
|
EXAMPLE_ZIP = 'filesystem.zip'
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
FileUtils.rm_f(EXAMPLE_ZIP)
|
|
10
11
|
|
|
11
|
-
Zip::File.open(EXAMPLE_ZIP,
|
|
12
|
+
Zip::File.open(EXAMPLE_ZIP, create: true) do |zf|
|
|
12
13
|
zf.file.open('file1.txt', 'w') { |os| os.write 'first file1.txt' }
|
|
13
14
|
zf.dir.mkdir('dir1')
|
|
14
15
|
zf.dir.chdir('dir1')
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'zip'
|
|
2
4
|
|
|
3
5
|
# This is a simple example which uses rubyzip to
|
|
@@ -21,7 +23,7 @@ class ZipFileGenerator
|
|
|
21
23
|
def write
|
|
22
24
|
entries = Dir.entries(@input_dir) - %w[. ..]
|
|
23
25
|
|
|
24
|
-
::Zip::File.open(@output_file,
|
|
26
|
+
::Zip::File.open(@output_file, create: true) do |zipfile|
|
|
25
27
|
write_entries entries, '', zipfile
|
|
26
28
|
end
|
|
27
29
|
end
|
data/samples/gtk_ruby_zip.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
$LOAD_PATH << '../lib'
|
|
4
5
|
|
|
@@ -9,7 +10,7 @@ require 'zip'
|
|
|
9
10
|
|
|
10
11
|
class MainApp < Gtk::Window
|
|
11
12
|
def initialize
|
|
12
|
-
super
|
|
13
|
+
super
|
|
13
14
|
set_usize(400, 256)
|
|
14
15
|
set_title('rubyzip')
|
|
15
16
|
signal_connect(Gtk::Window::SIGNAL_DESTROY) { Gtk.main_quit }
|
|
@@ -42,7 +43,8 @@ class MainApp < Gtk::Window
|
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
class ButtonPanel < Gtk::HButtonBox
|
|
45
|
-
attr_reader :
|
|
46
|
+
attr_reader :extract_button, :open_button
|
|
47
|
+
|
|
46
48
|
def initialize
|
|
47
49
|
super
|
|
48
50
|
set_layout(Gtk::BUTTONBOX_START)
|
|
@@ -72,7 +74,7 @@ class MainApp < Gtk::Window
|
|
|
72
74
|
@zipfile.each do |entry|
|
|
73
75
|
@clist.append([entry.name,
|
|
74
76
|
entry.size.to_s,
|
|
75
|
-
|
|
77
|
+
"#{100.0 * entry.compressedSize / entry.size}%"])
|
|
76
78
|
end
|
|
77
79
|
end
|
|
78
80
|
end
|
data/samples/qtzip.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
$VERBOSE = true
|
|
4
5
|
|
|
@@ -6,14 +7,14 @@ $LOAD_PATH << '../lib'
|
|
|
6
7
|
|
|
7
8
|
require 'Qt'
|
|
8
9
|
system('rbuic -o zipdialogui.rb zipdialogui.ui')
|
|
9
|
-
require 'zipdialogui
|
|
10
|
+
require 'zipdialogui'
|
|
10
11
|
require 'zip'
|
|
11
12
|
|
|
12
13
|
a = Qt::Application.new(ARGV)
|
|
13
14
|
|
|
14
15
|
class ZipDialog < ZipDialogUI
|
|
15
16
|
def initialize
|
|
16
|
-
super
|
|
17
|
+
super
|
|
17
18
|
connect(child('add_button'), SIGNAL('clicked()'),
|
|
18
19
|
self, SLOT('add_files()'))
|
|
19
20
|
connect(child('extract_button'), SIGNAL('clicked()'),
|
|
@@ -65,14 +66,14 @@ class ZipDialog < ZipDialogUI
|
|
|
65
66
|
end
|
|
66
67
|
puts "selected_items.size = #{selected_items.size}"
|
|
67
68
|
puts "unselected_items.size = #{unselected_items.size}"
|
|
68
|
-
items =
|
|
69
|
+
items = selected_items.empty? ? unselected_items : selected_items
|
|
69
70
|
puts "items.size = #{items.size}"
|
|
70
71
|
|
|
71
72
|
d = Qt::FileDialog.get_existing_directory(nil, self)
|
|
72
|
-
if
|
|
73
|
-
puts 'No directory chosen'
|
|
74
|
-
else
|
|
73
|
+
if d
|
|
75
74
|
zipfile { |zf| items.each { |e| zf.extract(e, File.join(d, e)) } }
|
|
75
|
+
else
|
|
76
|
+
puts 'No directory chosen'
|
|
76
77
|
end
|
|
77
78
|
end
|
|
78
79
|
|
data/samples/write_simple.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
$LOAD_PATH << '../lib'
|
|
4
5
|
|
|
5
6
|
require 'zip'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Zip::OutputStream.open('simple.zip') do |zos|
|
|
8
9
|
zos.put_next_entry 'entry.txt'
|
|
9
10
|
zos.puts 'Hello world'
|
|
10
11
|
end
|