rubyzip 1.3.0 → 3.0.0.alpha
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 +368 -0
- data/README.md +123 -46
- data/Rakefile +13 -6
- data/lib/zip/central_directory.rb +166 -116
- data/lib/zip/compressor.rb +3 -1
- data/lib/zip/constants.rb +77 -21
- data/lib/zip/crypto/decrypted_io.rb +42 -0
- data/lib/zip/crypto/encryption.rb +4 -2
- data/lib/zip/crypto/null_encryption.rb +5 -3
- data/lib/zip/crypto/traditional_encryption.rb +14 -12
- data/lib/zip/decompressor.rb +21 -2
- data/lib/zip/deflater.rb +10 -8
- data/lib/zip/dirtyable.rb +32 -0
- data/lib/zip/dos_time.rb +53 -12
- data/lib/zip/entry.rb +306 -184
- data/lib/zip/entry_set.rb +11 -7
- data/lib/zip/errors.rb +115 -15
- data/lib/zip/extra_field/generic.rb +11 -17
- data/lib/zip/extra_field/ntfs.rb +8 -2
- 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 +33 -0
- data/lib/zip/extra_field/zip64.rb +16 -7
- data/lib/zip/extra_field.rb +22 -26
- data/lib/zip/file.rb +196 -240
- data/lib/zip/file_split.rb +97 -0
- data/lib/zip/filesystem/dir.rb +86 -0
- data/lib/zip/filesystem/directory_iterator.rb +48 -0
- data/lib/zip/filesystem/file.rb +262 -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 +31 -584
- data/lib/zip/inflater.rb +27 -37
- data/lib/zip/input_stream.rb +67 -42
- data/lib/zip/ioextras/abstract_input_stream.rb +32 -16
- data/lib/zip/ioextras/abstract_output_stream.rb +5 -3
- data/lib/zip/ioextras.rb +7 -7
- data/lib/zip/null_compressor.rb +3 -1
- data/lib/zip/null_decompressor.rb +4 -10
- data/lib/zip/null_input_stream.rb +3 -1
- data/lib/zip/output_stream.rb +58 -43
- data/lib/zip/pass_thru_compressor.rb +5 -3
- data/lib/zip/pass_thru_decompressor.rb +16 -23
- data/lib/zip/streamable_directory.rb +6 -4
- data/lib/zip/streamable_stream.rb +9 -10
- data/lib/zip/version.rb +3 -1
- data/lib/zip.rb +19 -4
- data/rubyzip.gemspec +38 -0
- data/samples/example.rb +9 -4
- data/samples/example_filesystem.rb +3 -2
- data/samples/example_recursive.rb +3 -1
- data/samples/gtk_ruby_zip.rb +22 -20
- data/samples/qtzip.rb +12 -11
- data/samples/write_simple.rb +3 -4
- data/samples/zipfind.rb +24 -22
- metadata +86 -179
- 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/output_stream.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
1
5
|
module Zip
|
2
6
|
# ZipOutputStream is the basic class for writing zip files. It is
|
3
7
|
# possible to create a ZipOutputStream object directly, passing
|
@@ -18,46 +22,48 @@ module Zip
|
|
18
22
|
# class.
|
19
23
|
|
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)
|
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
|
41
46
|
@closed = false
|
42
47
|
@current_entry = nil
|
43
|
-
@comment = nil
|
44
48
|
end
|
45
49
|
|
46
50
|
# Same as #initialize but if a block is passed the opened
|
47
51
|
# stream is passed to the block and closed when the block
|
48
52
|
# returns.
|
49
53
|
class << self
|
50
|
-
def open(file_name, encrypter
|
54
|
+
def open(file_name, encrypter: nil)
|
51
55
|
return new(file_name) unless block_given?
|
52
|
-
|
56
|
+
|
57
|
+
zos = new(file_name, stream: false, encrypter: encrypter)
|
53
58
|
yield zos
|
54
59
|
ensure
|
55
60
|
zos.close if zos
|
56
61
|
end
|
57
62
|
|
58
63
|
# Same as #open but writes to a filestream instead
|
59
|
-
def write_buffer(io = ::StringIO.new
|
60
|
-
|
64
|
+
def write_buffer(io = ::StringIO.new, encrypter: nil)
|
65
|
+
io.binmode if io.respond_to?(:binmode)
|
66
|
+
zos = new(io, stream: true, encrypter: encrypter)
|
61
67
|
yield zos
|
62
68
|
zos.close_buffer
|
63
69
|
end
|
@@ -66,9 +72,10 @@ module Zip
|
|
66
72
|
# Closes the stream and writes the central directory to the zip file
|
67
73
|
def close
|
68
74
|
return if @closed
|
75
|
+
|
69
76
|
finalize_current_entry
|
70
77
|
update_local_headers
|
71
|
-
|
78
|
+
@cdir.write_to_stream(@output_stream)
|
72
79
|
@output_stream.close
|
73
80
|
@closed = true
|
74
81
|
end
|
@@ -76,37 +83,44 @@ module Zip
|
|
76
83
|
# Closes the stream and writes the central directory to the zip file
|
77
84
|
def close_buffer
|
78
85
|
return @output_stream if @closed
|
86
|
+
|
79
87
|
finalize_current_entry
|
80
88
|
update_local_headers
|
81
|
-
|
89
|
+
@cdir.write_to_stream(@output_stream)
|
82
90
|
@closed = true
|
91
|
+
@output_stream.flush
|
83
92
|
@output_stream
|
84
93
|
end
|
85
94
|
|
86
95
|
# Closes the current entry and opens a new for writing.
|
87
96
|
# +entry+ can be a ZipEntry object or a string.
|
88
|
-
def put_next_entry(
|
97
|
+
def put_next_entry(
|
98
|
+
entry_name, comment = '', extra = ExtraField.new,
|
99
|
+
compression_method = Entry::DEFLATED, level = Zip.default_compression
|
100
|
+
)
|
89
101
|
raise Error, 'zip stream is closed' if @closed
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
102
|
+
|
103
|
+
new_entry =
|
104
|
+
if entry_name.kind_of?(Entry) || entry_name.kind_of?(StreamableStream)
|
105
|
+
entry_name
|
106
|
+
else
|
107
|
+
Entry.new(
|
108
|
+
@file_name, entry_name.to_s, comment: comment, extra: extra,
|
109
|
+
compression_method: compression_method, compression_level: level
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
init_next_entry(new_entry)
|
101
114
|
@current_entry = new_entry
|
102
115
|
end
|
103
116
|
|
104
117
|
def copy_raw_entry(entry)
|
105
118
|
entry = entry.dup
|
106
119
|
raise Error, 'zip stream is closed' if @closed
|
107
|
-
raise Error, 'entry is not a ZipEntry' unless entry.
|
120
|
+
raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
|
121
|
+
|
108
122
|
finalize_current_entry
|
109
|
-
@
|
123
|
+
@cdir << entry
|
110
124
|
src_pos = entry.local_header_offset
|
111
125
|
entry.write_local_entry(@output_stream)
|
112
126
|
@compressor = NullCompressor.instance
|
@@ -123,51 +137,52 @@ module Zip
|
|
123
137
|
|
124
138
|
def finalize_current_entry
|
125
139
|
return unless @current_entry
|
140
|
+
|
126
141
|
finish
|
127
|
-
@current_entry.compressed_size = @output_stream.tell -
|
142
|
+
@current_entry.compressed_size = @output_stream.tell - \
|
143
|
+
@current_entry.local_header_offset - \
|
144
|
+
@current_entry.calculate_local_header_size
|
128
145
|
@current_entry.size = @compressor.size
|
129
146
|
@current_entry.crc = @compressor.crc
|
130
|
-
@output_stream << @encrypter.data_descriptor(
|
147
|
+
@output_stream << @encrypter.data_descriptor(
|
148
|
+
@current_entry.crc,
|
149
|
+
@current_entry.compressed_size,
|
150
|
+
@current_entry.size
|
151
|
+
)
|
131
152
|
@current_entry.gp_flags |= @encrypter.gp_flags
|
132
153
|
@current_entry = nil
|
133
154
|
@compressor = ::Zip::NullCompressor.instance
|
134
155
|
end
|
135
156
|
|
136
|
-
def init_next_entry(entry
|
157
|
+
def init_next_entry(entry)
|
137
158
|
finalize_current_entry
|
138
|
-
@
|
159
|
+
@cdir << entry
|
139
160
|
entry.write_local_entry(@output_stream)
|
140
161
|
@encrypter.reset!
|
141
162
|
@output_stream << @encrypter.header(entry.mtime)
|
142
|
-
@compressor = get_compressor(entry
|
163
|
+
@compressor = get_compressor(entry)
|
143
164
|
end
|
144
165
|
|
145
|
-
def get_compressor(entry
|
166
|
+
def get_compressor(entry)
|
146
167
|
case entry.compression_method
|
147
|
-
when Entry::DEFLATED
|
148
|
-
::Zip::Deflater.new(@output_stream,
|
149
|
-
when Entry::STORED
|
168
|
+
when Entry::DEFLATED
|
169
|
+
::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
|
170
|
+
when Entry::STORED
|
150
171
|
::Zip::PassThruCompressor.new(@output_stream)
|
151
172
|
else
|
152
|
-
raise ::Zip::CompressionMethodError,
|
153
|
-
"Invalid compression method: '#{entry.compression_method}'"
|
173
|
+
raise ::Zip::CompressionMethodError, entry.compression_method
|
154
174
|
end
|
155
175
|
end
|
156
176
|
|
157
177
|
def update_local_headers
|
158
178
|
pos = @output_stream.pos
|
159
|
-
@
|
179
|
+
@cdir.each do |entry|
|
160
180
|
@output_stream.pos = entry.local_header_offset
|
161
|
-
entry.write_local_entry(@output_stream, true)
|
181
|
+
entry.write_local_entry(@output_stream, rewrite: true)
|
162
182
|
end
|
163
183
|
@output_stream.pos = pos
|
164
184
|
end
|
165
185
|
|
166
|
-
def write_central_directory
|
167
|
-
cdir = CentralDirectory.new(@entry_set, @comment)
|
168
|
-
cdir.write_to_stream(@output_stream)
|
169
|
-
end
|
170
|
-
|
171
186
|
protected
|
172
187
|
|
173
188
|
def finish
|
@@ -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,31 @@
|
|
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(length = nil, outbuf = +'')
|
11
|
+
return (length.nil? || length.zero? ? '' : nil) if eof
|
17
12
|
|
18
|
-
if
|
19
|
-
|
13
|
+
if length.nil? || (@read_so_far + length) > decompressed_size
|
14
|
+
length = 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 += length
|
18
|
+
input_stream.read(length, outbuf)
|
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
|
-
alias eof
|
34
|
-
alias eof? input_finished?
|
25
|
+
alias eof? eof
|
35
26
|
end
|
27
|
+
|
28
|
+
::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
|
36
29
|
end
|
37
30
|
|
38
31
|
# 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
6
|
super(entry)
|
5
|
-
|
6
|
-
::File.dirname(zipfile)
|
7
|
-
else
|
8
|
-
nil
|
9
|
-
end
|
10
|
-
@temp_file = Tempfile.new(::File.basename(name), dirname)
|
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,13 @@
|
|
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/constants'
|
8
11
|
require 'zip/dos_time'
|
9
12
|
require 'zip/ioextras'
|
10
13
|
require 'rbconfig'
|
@@ -22,6 +25,7 @@ require 'zip/null_compressor'
|
|
22
25
|
require 'zip/null_input_stream'
|
23
26
|
require 'zip/pass_thru_compressor'
|
24
27
|
require 'zip/pass_thru_decompressor'
|
28
|
+
require 'zip/crypto/decrypted_io'
|
25
29
|
require 'zip/crypto/encryption'
|
26
30
|
require 'zip/crypto/null_encryption'
|
27
31
|
require 'zip/crypto/traditional_encryption'
|
@@ -29,9 +33,13 @@ require 'zip/inflater'
|
|
29
33
|
require 'zip/deflater'
|
30
34
|
require 'zip/streamable_stream'
|
31
35
|
require 'zip/streamable_directory'
|
32
|
-
require 'zip/constants'
|
33
36
|
require 'zip/errors'
|
34
37
|
|
38
|
+
# Rubyzip is a ruby module for reading and writing zip files.
|
39
|
+
#
|
40
|
+
# The main entry points are File, InputStream and OutputStream. For a
|
41
|
+
# file/directory interface in the style of the standard ruby ::File and
|
42
|
+
# ::Dir APIs then `require 'zip/filesystem'` and see FileSystem.
|
35
43
|
module Zip
|
36
44
|
extend self
|
37
45
|
attr_accessor :unicode_names,
|
@@ -45,6 +53,12 @@ module Zip
|
|
45
53
|
:force_entry_names_encoding,
|
46
54
|
:validate_entry_sizes
|
47
55
|
|
56
|
+
DEFAULT_RESTORE_OPTIONS = {
|
57
|
+
restore_ownership: false,
|
58
|
+
restore_permissions: true,
|
59
|
+
restore_times: true
|
60
|
+
}.freeze
|
61
|
+
|
48
62
|
def reset!
|
49
63
|
@_ran_once = false
|
50
64
|
@unicode_names = false
|
@@ -52,10 +66,11 @@ module Zip
|
|
52
66
|
@continue_on_exists_proc = false
|
53
67
|
@sort_entries = false
|
54
68
|
@default_compression = ::Zlib::DEFAULT_COMPRESSION
|
55
|
-
@write_zip64_support =
|
69
|
+
@write_zip64_support = true
|
56
70
|
@warn_invalid_date = true
|
57
71
|
@case_insensitive_match = false
|
58
|
-
@
|
72
|
+
@force_entry_names_encoding = nil
|
73
|
+
@validate_entry_sizes = true
|
59
74
|
end
|
60
75
|
|
61
76
|
def setup
|
data/rubyzip.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
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[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
|
+
}
|
27
|
+
|
28
|
+
s.required_ruby_version = '>= 2.5'
|
29
|
+
|
30
|
+
s.add_development_dependency 'minitest', '~> 5.4'
|
31
|
+
s.add_development_dependency 'rake', '~> 12.3.3'
|
32
|
+
s.add_development_dependency 'rdoc', '~> 6.4.0'
|
33
|
+
s.add_development_dependency 'rubocop', '~> 1.12.0'
|
34
|
+
s.add_development_dependency 'rubocop-performance', '~> 1.10.0'
|
35
|
+
s.add_development_dependency 'rubocop-rake', '~> 0.5.0'
|
36
|
+
s.add_development_dependency 'simplecov', '~> 0.18.0'
|
37
|
+
s.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
38
|
+
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,6 +1,7 @@
|
|
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
|
|
@@ -8,7 +9,7 @@ EXAMPLE_ZIP = 'filesystem.zip'
|
|
8
9
|
|
9
10
|
File.delete(EXAMPLE_ZIP) if File.exist?(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,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
|
4
|
+
$LOAD_PATH << '../lib'
|
4
5
|
|
5
6
|
$VERBOSE = true
|
6
7
|
|
@@ -18,14 +19,14 @@ class MainApp < Gtk::Window
|
|
18
19
|
add(box)
|
19
20
|
|
20
21
|
@zipfile = nil
|
21
|
-
@
|
22
|
-
@
|
22
|
+
@button_panel = ButtonPanel.new
|
23
|
+
@button_panel.open_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) do
|
23
24
|
show_file_selector
|
24
25
|
end
|
25
|
-
@
|
26
|
+
@button_panel.extract_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) do
|
26
27
|
puts 'Not implemented!'
|
27
28
|
end
|
28
|
-
box.pack_start(@
|
29
|
+
box.pack_start(@button_panel, false, false, 0)
|
29
30
|
|
30
31
|
sw = Gtk::ScrolledWindow.new
|
31
32
|
sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
|
@@ -42,27 +43,28 @@ 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)
|
49
51
|
set_spacing(0)
|
50
|
-
@
|
51
|
-
@
|
52
|
-
pack_start(@
|
53
|
-
pack_start(@
|
52
|
+
@open_button = Gtk::Button.new('Open archive')
|
53
|
+
@extract_button = Gtk::Button.new('Extract entry')
|
54
|
+
pack_start(@open_button)
|
55
|
+
pack_start(@extract_button)
|
54
56
|
end
|
55
57
|
end
|
56
58
|
|
57
59
|
def show_file_selector
|
58
|
-
@
|
59
|
-
@
|
60
|
-
@
|
61
|
-
open_zip(@
|
62
|
-
@
|
60
|
+
@file_selector = Gtk::FileSelection.new('Open zip file')
|
61
|
+
@file_selector.show
|
62
|
+
@file_selector.ok_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) do
|
63
|
+
open_zip(@file_selector.filename)
|
64
|
+
@file_selector.destroy
|
63
65
|
end
|
64
|
-
@
|
65
|
-
@
|
66
|
+
@file_selector.cancel_button.signal_connect(Gtk::Button::SIGNAL_CLICKED) do
|
67
|
+
@file_selector.destroy
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
@@ -72,13 +74,13 @@ 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
|
79
81
|
|
80
|
-
|
82
|
+
main_app = MainApp.new
|
81
83
|
|
82
|
-
|
84
|
+
main_app.show_all
|
83
85
|
|
84
86
|
Gtk.main
|
data/samples/qtzip.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
$VERBOSE = true
|
4
5
|
|
5
|
-
|
6
|
+
$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)
|
@@ -20,12 +21,12 @@ class ZipDialog < ZipDialogUI
|
|
20
21
|
self, SLOT('extract_files()'))
|
21
22
|
end
|
22
23
|
|
23
|
-
def zipfile(&
|
24
|
-
Zip::File.open(@zip_filename, &
|
24
|
+
def zipfile(&a_proc)
|
25
|
+
Zip::File.open(@zip_filename, &a_proc)
|
25
26
|
end
|
26
27
|
|
27
|
-
def each(&
|
28
|
-
Zip::File.foreach(@zip_filename, &
|
28
|
+
def each(&a_proc)
|
29
|
+
Zip::File.foreach(@zip_filename, &a_proc)
|
29
30
|
end
|
30
31
|
|
31
32
|
def refresh
|
@@ -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
|
|
@@ -80,7 +81,7 @@ class ZipDialog < ZipDialogUI
|
|
80
81
|
end
|
81
82
|
|
82
83
|
unless ARGV[0]
|
83
|
-
puts "usage: #{$
|
84
|
+
puts "usage: #{$PROGRAM_NAME} zipname"
|
84
85
|
exit
|
85
86
|
end
|
86
87
|
|