rubyzip 1.3.0 → 3.4.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 +516 -0
- data/LICENSE.md +24 -0
- data/README.md +213 -51
- data/Rakefile +17 -12
- data/lib/rubyzip.rb +3 -0
- data/lib/zip/central_directory.rb +196 -123
- data/lib/zip/compressor.rb +3 -1
- data/lib/zip/constants.rb +81 -21
- data/lib/zip/crypto/aes_encryption.rb +120 -0
- data/lib/zip/crypto/decrypted_io.rb +46 -0
- data/lib/zip/crypto/encryption.rb +4 -2
- data/lib/zip/crypto/null_encryption.rb +5 -13
- data/lib/zip/crypto/traditional_encryption.rb +22 -16
- data/lib/zip/decompressor.rb +21 -2
- data/lib/zip/deflater.rb +12 -8
- data/lib/zip/dirtyable.rb +32 -0
- data/lib/zip/dos_time.rb +65 -13
- data/lib/zip/entry.rb +433 -249
- data/lib/zip/entry_set.rb +13 -9
- data/lib/zip/errors.rb +152 -15
- data/lib/zip/extra_field/aes.rb +50 -0
- data/lib/zip/extra_field/generic.rb +18 -18
- data/lib/zip/extra_field/ntfs.rb +10 -4
- data/lib/zip/extra_field/old_unix.rb +6 -2
- data/lib/zip/extra_field/universal_time.rb +45 -13
- data/lib/zip/extra_field/unix.rb +7 -3
- data/lib/zip/extra_field/unknown.rb +35 -0
- data/lib/zip/extra_field/zip64.rb +23 -7
- data/lib/zip/extra_field.rb +31 -27
- data/lib/zip/file.rb +225 -241
- 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 +32 -585
- data/lib/zip/inflater.rb +28 -37
- data/lib/zip/input_stream.rb +113 -54
- data/lib/zip/ioextras/abstract_input_stream.rb +154 -55
- data/lib/zip/ioextras/abstract_output_stream.rb +13 -3
- data/lib/zip/ioextras.rb +8 -8
- data/lib/zip/null_compressor.rb +3 -1
- data/lib/zip/null_decompressor.rb +7 -12
- data/lib/zip/null_input_stream.rb +3 -1
- data/lib/zip/output_stream.rb +69 -50
- data/lib/zip/pass_thru_compressor.rb +5 -3
- data/lib/zip/pass_thru_decompressor.rb +17 -23
- data/lib/zip/streamable_directory.rb +6 -4
- data/lib/zip/streamable_stream.rb +10 -11
- data/lib/zip/version.rb +4 -1
- data/lib/zip.rb +32 -7
- data/rubyzip.gemspec +39 -0
- data/samples/example.rb +9 -4
- data/samples/example_filesystem.rb +4 -3
- data/samples/example_recursive.rb +3 -1
- data/samples/gtk_ruby_zip.rb +23 -21
- data/samples/qtzip.rb +13 -12
- data/samples/write_simple.rb +3 -4
- data/samples/zipfind.rb +24 -22
- metadata +85 -177
- data/TODO +0 -15
- data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
- 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/foo/bar/baz/foo.txt +0 -0
- data/test/data/globTest/foo.txt +0 -0
- data/test/data/globTest/food.txt +0 -0
- data/test/data/globTest.zip +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 -145
- data/test/file_permissions_test.rb +0 -65
- data/test/file_split_test.rb +0 -57
- data/test/file_test.rb +0 -666
- 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/null_compressor.rb
CHANGED
|
@@ -1,24 +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
|
-
def
|
|
6
|
-
nil
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def produce_input
|
|
7
|
+
def read(_length = nil, _outbuf = nil)
|
|
10
8
|
nil
|
|
11
9
|
end
|
|
12
10
|
|
|
13
|
-
def
|
|
14
|
-
true
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def eof
|
|
11
|
+
def eof?
|
|
18
12
|
true
|
|
19
13
|
end
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
# Alias for compatibility. Remove for version 4.
|
|
16
|
+
alias eof eof?
|
|
22
17
|
end
|
|
23
18
|
end
|
|
24
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,48 +21,52 @@ 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, stream
|
|
32
|
+
def initialize(file_name, stream: false, encrypter: nil, suppress_extra_fields: false)
|
|
28
33
|
super()
|
|
29
34
|
@file_name = file_name
|
|
30
35
|
@output_stream = if stream
|
|
31
|
-
iostream = @file_name.dup
|
|
36
|
+
iostream = Zip::RUNNING_ON_WINDOWS ? @file_name : @file_name.dup
|
|
32
37
|
iostream.reopen(@file_name)
|
|
33
38
|
iostream.rewind
|
|
34
39
|
iostream
|
|
35
40
|
else
|
|
36
41
|
::File.new(@file_name, 'wb')
|
|
37
42
|
end
|
|
38
|
-
@
|
|
43
|
+
@cdir = ::Zip::CentralDirectory.new
|
|
39
44
|
@compressor = ::Zip::NullCompressor.instance
|
|
40
45
|
@encrypter = encrypter || ::Zip::NullEncrypter.new
|
|
46
|
+
@suppress_extra_fields = suppress_extra_fields
|
|
41
47
|
@closed = false
|
|
42
48
|
@current_entry = nil
|
|
43
|
-
@comment = nil
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
# Same as #initialize but if a block is passed the opened
|
|
47
|
-
# stream is passed to the block and closed when the block
|
|
48
|
-
# returns.
|
|
49
51
|
class << self
|
|
50
|
-
|
|
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)
|
|
51
56
|
return new(file_name) unless block_given?
|
|
52
|
-
|
|
57
|
+
|
|
58
|
+
zos = new(file_name, stream: false, encrypter: encrypter,
|
|
59
|
+
suppress_extra_fields: suppress_extra_fields)
|
|
53
60
|
yield zos
|
|
54
61
|
ensure
|
|
55
62
|
zos.close if zos
|
|
56
63
|
end
|
|
57
64
|
|
|
58
65
|
# Same as #open but writes to a filestream instead
|
|
59
|
-
def write_buffer(io = ::StringIO.new
|
|
60
|
-
|
|
66
|
+
def write_buffer(io = ::StringIO.new, encrypter: nil, suppress_extra_fields: false)
|
|
67
|
+
io.binmode if io.respond_to?(:binmode)
|
|
68
|
+
zos = new(io, stream: true, encrypter: encrypter,
|
|
69
|
+
suppress_extra_fields: suppress_extra_fields)
|
|
61
70
|
yield zos
|
|
62
71
|
zos.close_buffer
|
|
63
72
|
end
|
|
@@ -66,9 +75,10 @@ module Zip
|
|
|
66
75
|
# Closes the stream and writes the central directory to the zip file
|
|
67
76
|
def close
|
|
68
77
|
return if @closed
|
|
78
|
+
|
|
69
79
|
finalize_current_entry
|
|
70
80
|
update_local_headers
|
|
71
|
-
|
|
81
|
+
@cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
72
82
|
@output_stream.close
|
|
73
83
|
@closed = true
|
|
74
84
|
end
|
|
@@ -76,37 +86,44 @@ module Zip
|
|
|
76
86
|
# Closes the stream and writes the central directory to the zip file
|
|
77
87
|
def close_buffer
|
|
78
88
|
return @output_stream if @closed
|
|
89
|
+
|
|
79
90
|
finalize_current_entry
|
|
80
91
|
update_local_headers
|
|
81
|
-
|
|
92
|
+
@cdir.write_to_stream(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
82
93
|
@closed = true
|
|
94
|
+
@output_stream.flush
|
|
83
95
|
@output_stream
|
|
84
96
|
end
|
|
85
97
|
|
|
86
98
|
# Closes the current entry and opens a new for writing.
|
|
87
99
|
# +entry+ can be a ZipEntry object or a string.
|
|
88
|
-
def put_next_entry(
|
|
100
|
+
def put_next_entry(
|
|
101
|
+
entry_name, comment = '', extra = ExtraField.new,
|
|
102
|
+
compression_method = Entry::DEFLATED, level = Zip.default_compression
|
|
103
|
+
)
|
|
89
104
|
raise Error, 'zip stream is closed' if @closed
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
|
|
106
|
+
new_entry =
|
|
107
|
+
if entry_name.kind_of?(Entry) || entry_name.kind_of?(StreamableStream)
|
|
108
|
+
entry_name
|
|
109
|
+
else
|
|
110
|
+
Entry.new(
|
|
111
|
+
@file_name, entry_name.to_s, comment: comment, extra: extra,
|
|
112
|
+
compression_method: compression_method, compression_level: level
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
init_next_entry(new_entry)
|
|
101
117
|
@current_entry = new_entry
|
|
102
118
|
end
|
|
103
119
|
|
|
104
|
-
def copy_raw_entry(entry)
|
|
120
|
+
def copy_raw_entry(entry) # :nodoc:
|
|
105
121
|
entry = entry.dup
|
|
106
122
|
raise Error, 'zip stream is closed' if @closed
|
|
107
|
-
raise Error, 'entry is not a ZipEntry' unless entry.
|
|
123
|
+
raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
|
|
124
|
+
|
|
108
125
|
finalize_current_entry
|
|
109
|
-
@
|
|
126
|
+
@cdir << entry
|
|
110
127
|
src_pos = entry.local_header_offset
|
|
111
128
|
entry.write_local_entry(@output_stream)
|
|
112
129
|
@compressor = NullCompressor.instance
|
|
@@ -123,54 +140,56 @@ module Zip
|
|
|
123
140
|
|
|
124
141
|
def finalize_current_entry
|
|
125
142
|
return unless @current_entry
|
|
143
|
+
|
|
126
144
|
finish
|
|
127
|
-
@current_entry.compressed_size = @output_stream.tell -
|
|
145
|
+
@current_entry.compressed_size = @output_stream.tell -
|
|
146
|
+
@current_entry.local_header_offset -
|
|
147
|
+
@current_entry.calculate_local_header_size
|
|
128
148
|
@current_entry.size = @compressor.size
|
|
129
149
|
@current_entry.crc = @compressor.crc
|
|
130
|
-
@output_stream << @encrypter.data_descriptor(
|
|
150
|
+
@output_stream << @encrypter.data_descriptor(
|
|
151
|
+
@current_entry.crc,
|
|
152
|
+
@current_entry.compressed_size,
|
|
153
|
+
@current_entry.size
|
|
154
|
+
)
|
|
131
155
|
@current_entry.gp_flags |= @encrypter.gp_flags
|
|
132
156
|
@current_entry = nil
|
|
133
157
|
@compressor = ::Zip::NullCompressor.instance
|
|
134
158
|
end
|
|
135
159
|
|
|
136
|
-
def init_next_entry(entry
|
|
160
|
+
def init_next_entry(entry)
|
|
137
161
|
finalize_current_entry
|
|
138
|
-
@
|
|
139
|
-
entry.write_local_entry(@output_stream)
|
|
162
|
+
@cdir << entry
|
|
163
|
+
entry.write_local_entry(@output_stream, suppress_extra_fields: @suppress_extra_fields)
|
|
140
164
|
@encrypter.reset!
|
|
141
165
|
@output_stream << @encrypter.header(entry.mtime)
|
|
142
|
-
@compressor = get_compressor(entry
|
|
166
|
+
@compressor = get_compressor(entry)
|
|
143
167
|
end
|
|
144
168
|
|
|
145
|
-
def get_compressor(entry
|
|
169
|
+
def get_compressor(entry)
|
|
146
170
|
case entry.compression_method
|
|
147
|
-
when Entry::DEFLATED
|
|
148
|
-
::Zip::Deflater.new(@output_stream,
|
|
149
|
-
when Entry::STORED
|
|
171
|
+
when Entry::DEFLATED
|
|
172
|
+
::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
|
|
173
|
+
when Entry::STORED
|
|
150
174
|
::Zip::PassThruCompressor.new(@output_stream)
|
|
151
175
|
else
|
|
152
|
-
raise ::Zip::CompressionMethodError,
|
|
153
|
-
"Invalid compression method: '#{entry.compression_method}'"
|
|
176
|
+
raise ::Zip::CompressionMethodError, entry.compression_method
|
|
154
177
|
end
|
|
155
178
|
end
|
|
156
179
|
|
|
157
180
|
def update_local_headers
|
|
158
181
|
pos = @output_stream.pos
|
|
159
|
-
@
|
|
182
|
+
@cdir.each do |entry|
|
|
160
183
|
@output_stream.pos = entry.local_header_offset
|
|
161
|
-
entry.write_local_entry(@output_stream,
|
|
184
|
+
entry.write_local_entry(@output_stream, suppress_extra_fields: @suppress_extra_fields,
|
|
185
|
+
rewrite: true)
|
|
162
186
|
end
|
|
163
187
|
@output_stream.pos = pos
|
|
164
188
|
end
|
|
165
189
|
|
|
166
|
-
def write_central_directory
|
|
167
|
-
cdir = CentralDirectory.new(@entry_set, @comment)
|
|
168
|
-
cdir.write_to_stream(@output_stream)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
190
|
protected
|
|
172
191
|
|
|
173
|
-
def finish
|
|
192
|
+
def finish # :nodoc:
|
|
174
193
|
@compressor.finish
|
|
175
194
|
end
|
|
176
195
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
class PassThruCompressor < Compressor
|
|
3
|
-
def initialize(
|
|
4
|
+
class PassThruCompressor < Compressor # :nodoc:all
|
|
5
|
+
def initialize(output_stream)
|
|
4
6
|
super()
|
|
5
|
-
@output_stream =
|
|
7
|
+
@output_stream = output_stream
|
|
6
8
|
@crc = Zlib.crc32
|
|
7
9
|
@size = 0
|
|
8
10
|
end
|
|
@@ -1,38 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
class PassThruDecompressor < Decompressor
|
|
3
|
-
def initialize(
|
|
4
|
-
super
|
|
5
|
-
@chars_to_read = chars_to_read
|
|
4
|
+
class PassThruDecompressor < Decompressor # :nodoc:all
|
|
5
|
+
def initialize(*args)
|
|
6
|
+
super
|
|
6
7
|
@read_so_far = 0
|
|
7
|
-
@has_returned_empty_string = false
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def
|
|
11
|
-
if
|
|
12
|
-
has_returned_empty_string_val = @has_returned_empty_string
|
|
13
|
-
@has_returned_empty_string = true
|
|
14
|
-
return '' unless has_returned_empty_string_val
|
|
15
|
-
return
|
|
16
|
-
end
|
|
10
|
+
def read(maxlen = nil)
|
|
11
|
+
return (maxlen.nil? || maxlen.zero? ? '' : nil) if eof?
|
|
17
12
|
|
|
18
|
-
if
|
|
19
|
-
|
|
13
|
+
if maxlen.nil? || (@read_so_far + maxlen) > decompressed_size
|
|
14
|
+
maxlen = decompressed_size - @read_so_far
|
|
20
15
|
end
|
|
21
|
-
@read_so_far += number_of_bytes
|
|
22
|
-
@input_stream.read(number_of_bytes, buf)
|
|
23
|
-
end
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
@read_so_far += maxlen
|
|
18
|
+
input_stream.read(maxlen)
|
|
27
19
|
end
|
|
28
20
|
|
|
29
|
-
def
|
|
30
|
-
@read_so_far >=
|
|
21
|
+
def eof?
|
|
22
|
+
@read_so_far >= decompressed_size
|
|
31
23
|
end
|
|
32
24
|
|
|
33
|
-
|
|
34
|
-
alias eof
|
|
25
|
+
# Alias for compatibility. Remove for version 4.
|
|
26
|
+
alias eof eof?
|
|
35
27
|
end
|
|
28
|
+
|
|
29
|
+
::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
|
|
36
30
|
end
|
|
37
31
|
|
|
38
32
|
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
class StreamableDirectory < Entry
|
|
3
|
-
def initialize(zipfile, entry,
|
|
4
|
+
class StreamableDirectory < Entry # :nodoc:
|
|
5
|
+
def initialize(zipfile, entry, src_path = nil, permission = nil)
|
|
4
6
|
super(zipfile, entry)
|
|
5
7
|
|
|
6
8
|
@ftype = :directory
|
|
7
|
-
entry.get_extra_attributes_from_path(
|
|
8
|
-
@unix_perms =
|
|
9
|
+
entry.get_extra_attributes_from_path(src_path) if src_path
|
|
10
|
+
@unix_perms = permission if permission
|
|
9
11
|
end
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Zip
|
|
2
|
-
class StreamableStream < DelegateClass(Entry) # nodoc:all
|
|
4
|
+
class StreamableStream < DelegateClass(Entry) # :nodoc:all
|
|
3
5
|
def initialize(entry)
|
|
4
|
-
super
|
|
5
|
-
|
|
6
|
-
::File.dirname(zipfile)
|
|
7
|
-
else
|
|
8
|
-
nil
|
|
9
|
-
end
|
|
10
|
-
@temp_file = Tempfile.new(::File.basename(name), dirname)
|
|
6
|
+
super
|
|
7
|
+
@temp_file = Tempfile.new(::File.basename(name))
|
|
11
8
|
@temp_file.binmode
|
|
12
9
|
end
|
|
13
10
|
|
|
@@ -27,6 +24,7 @@ module Zip
|
|
|
27
24
|
unless @temp_file.closed?
|
|
28
25
|
raise StandardError, "cannot open entry for reading while its open for writing - #{name}"
|
|
29
26
|
end
|
|
27
|
+
|
|
30
28
|
@temp_file.open # reopens tempfile from top
|
|
31
29
|
@temp_file.binmode
|
|
32
30
|
if block_given?
|
|
@@ -40,12 +38,13 @@ module Zip
|
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
40
|
|
|
43
|
-
def write_to_zip_output_stream(
|
|
44
|
-
|
|
45
|
-
get_input_stream { |is| ::Zip::IOExtras.copy_stream(
|
|
41
|
+
def write_to_zip_output_stream(output_stream)
|
|
42
|
+
output_stream.put_next_entry(self)
|
|
43
|
+
get_input_stream { |is| ::Zip::IOExtras.copy_stream(output_stream, is) }
|
|
46
44
|
end
|
|
47
45
|
|
|
48
46
|
def clean_up
|
|
47
|
+
super
|
|
49
48
|
@temp_file.unlink
|
|
50
49
|
end
|
|
51
50
|
end
|
data/lib/zip/version.rb
CHANGED
data/lib/zip.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'English'
|
|
1
4
|
require 'delegate'
|
|
2
5
|
require 'singleton'
|
|
3
6
|
require 'tempfile'
|
|
4
|
-
require 'tmpdir'
|
|
5
7
|
require 'fileutils'
|
|
6
8
|
require 'stringio'
|
|
7
9
|
require 'zlib'
|
|
10
|
+
require 'zip/version'
|
|
11
|
+
require 'zip/constants'
|
|
8
12
|
require 'zip/dos_time'
|
|
9
13
|
require 'zip/ioextras'
|
|
10
14
|
require 'rbconfig'
|
|
@@ -22,18 +26,25 @@ require 'zip/null_compressor'
|
|
|
22
26
|
require 'zip/null_input_stream'
|
|
23
27
|
require 'zip/pass_thru_compressor'
|
|
24
28
|
require 'zip/pass_thru_decompressor'
|
|
29
|
+
require 'zip/crypto/decrypted_io'
|
|
25
30
|
require 'zip/crypto/encryption'
|
|
26
31
|
require 'zip/crypto/null_encryption'
|
|
27
32
|
require 'zip/crypto/traditional_encryption'
|
|
33
|
+
require 'zip/crypto/aes_encryption'
|
|
28
34
|
require 'zip/inflater'
|
|
29
35
|
require 'zip/deflater'
|
|
30
36
|
require 'zip/streamable_stream'
|
|
31
37
|
require 'zip/streamable_directory'
|
|
32
|
-
require 'zip/constants'
|
|
33
38
|
require 'zip/errors'
|
|
34
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.
|
|
35
45
|
module Zip
|
|
36
46
|
extend self
|
|
47
|
+
|
|
37
48
|
attr_accessor :unicode_names,
|
|
38
49
|
:on_exists_proc,
|
|
39
50
|
:continue_on_exists_proc,
|
|
@@ -43,21 +54,35 @@ module Zip
|
|
|
43
54
|
:warn_invalid_date,
|
|
44
55
|
:case_insensitive_match,
|
|
45
56
|
:force_entry_names_encoding,
|
|
46
|
-
: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
|
|
47
69
|
|
|
48
|
-
def reset!
|
|
70
|
+
def reset! # :nodoc:
|
|
49
71
|
@_ran_once = false
|
|
50
72
|
@unicode_names = false
|
|
51
73
|
@on_exists_proc = false
|
|
52
74
|
@continue_on_exists_proc = false
|
|
53
75
|
@sort_entries = false
|
|
54
|
-
@default_compression =
|
|
55
|
-
@write_zip64_support =
|
|
76
|
+
@default_compression = Zlib::DEFAULT_COMPRESSION
|
|
77
|
+
@write_zip64_support = true
|
|
56
78
|
@warn_invalid_date = true
|
|
57
79
|
@case_insensitive_match = false
|
|
58
|
-
@
|
|
80
|
+
@force_entry_names_encoding = nil
|
|
81
|
+
@validate_entry_sizes = true
|
|
82
|
+
@validate_declared_number_of_entries = false # Set this to `true` in v4.0.0?
|
|
59
83
|
end
|
|
60
84
|
|
|
85
|
+
# Set options for RubyZip in one block.
|
|
61
86
|
def setup
|
|
62
87
|
yield self unless @_ran_once
|
|
63
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,6 +1,7 @@
|
|
|
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')
|
|
5
6
|
|
|
6
7
|
require 'zip'
|
|
@@ -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,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
$LOAD_PATH << '../lib'
|
|
4
5
|
|
|
5
6
|
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
|