rubyzip 2.3.1 → 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 +122 -39
- data/Rakefile +11 -7
- data/lib/zip/central_directory.rb +164 -118
- data/lib/zip/compressor.rb +3 -1
- data/lib/zip/constants.rb +25 -21
- data/lib/zip/crypto/decrypted_io.rb +3 -1
- data/lib/zip/crypto/encryption.rb +4 -2
- data/lib/zip/crypto/null_encryption.rb +5 -3
- data/lib/zip/crypto/traditional_encryption.rb +5 -3
- data/lib/zip/decompressor.rb +4 -3
- data/lib/zip/deflater.rb +10 -8
- data/lib/zip/dirtyable.rb +32 -0
- data/lib/zip/dos_time.rb +41 -5
- data/lib/zip/entry.rb +273 -170
- data/lib/zip/entry_set.rb +9 -7
- data/lib/zip/errors.rb +115 -16
- data/lib/zip/extra_field/generic.rb +3 -10
- data/lib/zip/extra_field/ntfs.rb +4 -2
- data/lib/zip/extra_field/old_unix.rb +3 -1
- data/lib/zip/extra_field/universal_time.rb +3 -1
- data/lib/zip/extra_field/unix.rb +5 -3
- data/lib/zip/extra_field/unknown.rb +33 -0
- data/lib/zip/extra_field/zip64.rb +12 -5
- data/lib/zip/extra_field.rb +15 -21
- data/lib/zip/file.rb +152 -221
- 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 +26 -595
- data/lib/zip/inflater.rb +6 -4
- data/lib/zip/input_stream.rb +43 -25
- data/lib/zip/ioextras/abstract_input_stream.rb +13 -8
- data/lib/zip/ioextras/abstract_output_stream.rb +5 -3
- data/lib/zip/ioextras.rb +6 -6
- data/lib/zip/null_compressor.rb +3 -1
- data/lib/zip/null_decompressor.rb +3 -1
- data/lib/zip/null_input_stream.rb +3 -1
- data/lib/zip/output_stream.rb +45 -39
- data/lib/zip/pass_thru_compressor.rb +3 -1
- data/lib/zip/pass_thru_decompressor.rb +4 -2
- data/lib/zip/streamable_directory.rb +3 -1
- data/lib/zip/streamable_stream.rb +3 -0
- data/lib/zip/version.rb +3 -1
- data/lib/zip.rb +15 -22
- data/rubyzip.gemspec +38 -0
- data/samples/example.rb +8 -3
- data/samples/example_filesystem.rb +2 -1
- data/samples/example_recursive.rb +3 -1
- data/samples/gtk_ruby_zip.rb +4 -2
- data/samples/qtzip.rb +6 -5
- data/samples/write_simple.rb +1 -0
- data/samples/zipfind.rb +1 -0
- metadata +83 -35
- data/TODO +0 -15
- data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
data/lib/zip/input_stream.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
4
|
# InputStream is the basic class for reading zip entries in a
|
3
5
|
# zip file. It is possible to create a InputStream object directly,
|
@@ -49,24 +51,30 @@ module Zip
|
|
49
51
|
#
|
50
52
|
# @param context [String||IO||StringIO] file path or IO/StringIO object
|
51
53
|
# @param offset [Integer] offset in the IO/StringIO
|
52
|
-
def initialize(context, offset
|
54
|
+
def initialize(context, offset: 0, decrypter: nil)
|
53
55
|
super()
|
54
|
-
@archive_io
|
55
|
-
@decompressor
|
56
|
-
@decrypter
|
56
|
+
@archive_io = get_io(context, offset)
|
57
|
+
@decompressor = ::Zip::NullDecompressor
|
58
|
+
@decrypter = decrypter || ::Zip::NullDecrypter.new
|
57
59
|
@current_entry = nil
|
60
|
+
@complete_entry = nil
|
58
61
|
end
|
59
62
|
|
60
63
|
def close
|
61
64
|
@archive_io.close
|
62
65
|
end
|
63
66
|
|
64
|
-
# Returns
|
65
|
-
# method on a newly created
|
66
|
-
# the first entry in the archive.
|
67
|
-
# no more entries.
|
67
|
+
# Returns an Entry object and positions the stream at the beginning of
|
68
|
+
# the entry data. It is necessary to call this method on a newly created
|
69
|
+
# InputStream before reading from the first entry in the archive.
|
70
|
+
# Returns nil when there are no more entries.
|
68
71
|
def get_next_entry
|
69
|
-
@
|
72
|
+
unless @current_entry.nil?
|
73
|
+
raise StreamingError, @current_entry if @current_entry.incomplete?
|
74
|
+
|
75
|
+
@archive_io.seek(@current_entry.next_header_offset, IO::SEEK_SET)
|
76
|
+
end
|
77
|
+
|
70
78
|
open_entry
|
71
79
|
end
|
72
80
|
|
@@ -85,12 +93,19 @@ module Zip
|
|
85
93
|
@decompressor.read(length, outbuf)
|
86
94
|
end
|
87
95
|
|
96
|
+
# Returns the size of the current entry, or `nil` if there isn't one.
|
97
|
+
def size
|
98
|
+
return if @current_entry.nil?
|
99
|
+
|
100
|
+
@current_entry.size
|
101
|
+
end
|
102
|
+
|
88
103
|
class << self
|
89
104
|
# Same as #initialize but if a block is passed the opened
|
90
105
|
# stream is passed to the block and closed when the block
|
91
106
|
# returns.
|
92
|
-
def open(filename_or_io, offset
|
93
|
-
zio = new(filename_or_io, offset, decrypter)
|
107
|
+
def open(filename_or_io, offset: 0, decrypter: nil)
|
108
|
+
zio = new(filename_or_io, offset: offset, decrypter: decrypter)
|
94
109
|
return zio unless block_given?
|
95
110
|
|
96
111
|
begin
|
@@ -100,9 +115,9 @@ module Zip
|
|
100
115
|
end
|
101
116
|
end
|
102
117
|
|
103
|
-
def open_buffer(filename_or_io, offset
|
118
|
+
def open_buffer(filename_or_io, offset: 0)
|
104
119
|
warn 'open_buffer is deprecated!!! Use open instead!'
|
105
|
-
::Zip::InputStream.open(filename_or_io, offset)
|
120
|
+
::Zip::InputStream.open(filename_or_io, offset: offset)
|
106
121
|
end
|
107
122
|
end
|
108
123
|
|
@@ -122,17 +137,18 @@ module Zip
|
|
122
137
|
|
123
138
|
def open_entry
|
124
139
|
@current_entry = ::Zip::Entry.read_local_entry(@archive_io)
|
125
|
-
if @current_entry
|
126
|
-
|
140
|
+
return if @current_entry.nil?
|
141
|
+
|
142
|
+
if @current_entry.encrypted? && @decrypter.kind_of?(NullDecrypter)
|
143
|
+
raise Error,
|
144
|
+
'A password is required to decode this zip file'
|
127
145
|
end
|
128
146
|
|
129
|
-
if @current_entry
|
130
|
-
&&
|
131
|
-
|
132
|
-
raise GPFBit3Error,
|
133
|
-
'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
|
134
|
-
'Please use ::Zip::File instead of ::Zip::InputStream'
|
147
|
+
if @current_entry.incomplete? && @current_entry.compressed_size == 0 \
|
148
|
+
&& !@complete_entry
|
149
|
+
raise StreamingError, @current_entry
|
135
150
|
end
|
151
|
+
|
136
152
|
@decrypted_io = get_decrypted_io
|
137
153
|
@decompressor = get_decompressor
|
138
154
|
flush
|
@@ -150,16 +166,18 @@ module Zip
|
|
150
166
|
return ::Zip::NullDecompressor if @current_entry.nil?
|
151
167
|
|
152
168
|
decompressed_size =
|
153
|
-
if @current_entry.incomplete? && @current_entry.crc == 0
|
169
|
+
if @current_entry.incomplete? && @current_entry.crc == 0 \
|
170
|
+
&& @current_entry.size == 0 && @complete_entry
|
154
171
|
@complete_entry.size
|
155
172
|
else
|
156
173
|
@current_entry.size
|
157
174
|
end
|
158
175
|
|
159
|
-
decompressor_class = ::Zip::Decompressor.find_by_compression_method(
|
176
|
+
decompressor_class = ::Zip::Decompressor.find_by_compression_method(
|
177
|
+
@current_entry.compression_method
|
178
|
+
)
|
160
179
|
if decompressor_class.nil?
|
161
|
-
raise ::Zip::CompressionMethodError,
|
162
|
-
"Unsupported compression method #{@current_entry.compression_method}"
|
180
|
+
raise ::Zip::CompressionMethodError, @current_entry.compression_method
|
163
181
|
end
|
164
182
|
|
165
183
|
decompressor_class.new(@decrypted_io, decompressed_size)
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
module IOExtras
|
4
|
+
module IOExtras # :nodoc:
|
3
5
|
# Implements many of the convenience methods of IO
|
4
6
|
# such as gets, getc, readline and readlines
|
5
7
|
# depends on: input_finished?, produce_input and read
|
6
|
-
module AbstractInputStream
|
8
|
+
module AbstractInputStream # :nodoc:
|
7
9
|
include Enumerable
|
8
10
|
include FakeIO
|
9
11
|
|
@@ -11,15 +13,15 @@ module Zip
|
|
11
13
|
super
|
12
14
|
@lineno = 0
|
13
15
|
@pos = 0
|
14
|
-
@output_buffer = ''
|
16
|
+
@output_buffer = +''
|
15
17
|
end
|
16
18
|
|
17
19
|
attr_accessor :lineno
|
18
20
|
attr_reader :pos
|
19
21
|
|
20
|
-
def read(number_of_bytes = nil, buf = '')
|
22
|
+
def read(number_of_bytes = nil, buf = +'')
|
21
23
|
tbuf = if @output_buffer.bytesize > 0
|
22
|
-
if number_of_bytes <= @output_buffer.bytesize
|
24
|
+
if number_of_bytes && number_of_bytes <= @output_buffer.bytesize
|
23
25
|
@output_buffer.slice!(0, number_of_bytes)
|
24
26
|
else
|
25
27
|
number_of_bytes -= @output_buffer.bytesize if number_of_bytes
|
@@ -34,7 +36,7 @@ module Zip
|
|
34
36
|
end
|
35
37
|
|
36
38
|
if tbuf.nil? || tbuf.empty?
|
37
|
-
return nil if number_of_bytes
|
39
|
+
return nil if number_of_bytes&.positive?
|
38
40
|
|
39
41
|
return ''
|
40
42
|
end
|
@@ -82,7 +84,10 @@ module Zip
|
|
82
84
|
@output_buffer << produce_input
|
83
85
|
over_limit = (number_of_bytes && @output_buffer.bytesize >= number_of_bytes)
|
84
86
|
end
|
85
|
-
sep_index = [
|
87
|
+
sep_index = [
|
88
|
+
match_index + a_sep_string.bytesize,
|
89
|
+
number_of_bytes || @output_buffer.bytesize
|
90
|
+
].min
|
86
91
|
@pos += sep_index
|
87
92
|
@output_buffer.slice!(0...sep_index)
|
88
93
|
end
|
@@ -93,7 +98,7 @@ module Zip
|
|
93
98
|
|
94
99
|
def flush
|
95
100
|
ret_val = @output_buffer
|
96
|
-
@output_buffer = ''
|
101
|
+
@output_buffer = +''
|
97
102
|
ret_val
|
98
103
|
end
|
99
104
|
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
module IOExtras
|
4
|
+
module IOExtras # :nodoc:
|
3
5
|
# Implements many of the output convenience methods of IO.
|
4
6
|
# relies on <<
|
5
|
-
module AbstractOutputStream
|
7
|
+
module AbstractOutputStream # :nodoc:
|
6
8
|
include FakeIO
|
7
9
|
|
8
10
|
def write(data)
|
@@ -11,7 +13,7 @@ module Zip
|
|
11
13
|
end
|
12
14
|
|
13
15
|
def print(*params)
|
14
|
-
self << params.join
|
16
|
+
self << params.join << $OUTPUT_RECORD_SEPARATOR.to_s
|
15
17
|
end
|
16
18
|
|
17
19
|
def printf(a_format_string, *params)
|
data/lib/zip/ioextras.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
module IOExtras
|
4
|
+
module IOExtras # :nodoc:
|
3
5
|
CHUNK_SIZE = 131_072
|
4
6
|
|
5
|
-
RANGE_ALL = 0..-1
|
6
|
-
|
7
7
|
class << self
|
8
8
|
def copy_stream(ostream, istream)
|
9
|
-
ostream.write(istream.read(CHUNK_SIZE, '')) until istream.eof?
|
9
|
+
ostream.write(istream.read(CHUNK_SIZE, +'')) until istream.eof?
|
10
10
|
end
|
11
11
|
|
12
12
|
def copy_stream_n(ostream, istream, nbytes)
|
13
13
|
toread = nbytes
|
14
14
|
while toread > 0 && !istream.eof?
|
15
15
|
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
|
16
|
-
ostream.write(istream.read(tr, ''))
|
16
|
+
ostream.write(istream.read(tr, +''))
|
17
17
|
toread -= tr
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
# Implements kind_of? in order to pretend to be an IO object
|
23
|
-
module FakeIO
|
23
|
+
module FakeIO # :nodoc:
|
24
24
|
def kind_of?(object)
|
25
25
|
object == IO || super
|
26
26
|
end
|
data/lib/zip/null_compressor.rb
CHANGED
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,48 +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
|
|
53
|
-
zos = new(file_name, false, encrypter)
|
57
|
+
zos = new(file_name, stream: false, encrypter: encrypter)
|
54
58
|
yield zos
|
55
59
|
ensure
|
56
60
|
zos.close if zos
|
57
61
|
end
|
58
62
|
|
59
63
|
# Same as #open but writes to a filestream instead
|
60
|
-
def write_buffer(io = ::StringIO.new
|
64
|
+
def write_buffer(io = ::StringIO.new, encrypter: nil)
|
61
65
|
io.binmode if io.respond_to?(:binmode)
|
62
|
-
zos = new(io, true, encrypter)
|
66
|
+
zos = new(io, stream: true, encrypter: encrypter)
|
63
67
|
yield zos
|
64
68
|
zos.close_buffer
|
65
69
|
end
|
@@ -71,7 +75,7 @@ module Zip
|
|
71
75
|
|
72
76
|
finalize_current_entry
|
73
77
|
update_local_headers
|
74
|
-
|
78
|
+
@cdir.write_to_stream(@output_stream)
|
75
79
|
@output_stream.close
|
76
80
|
@closed = true
|
77
81
|
end
|
@@ -82,27 +86,31 @@ module Zip
|
|
82
86
|
|
83
87
|
finalize_current_entry
|
84
88
|
update_local_headers
|
85
|
-
|
89
|
+
@cdir.write_to_stream(@output_stream)
|
86
90
|
@closed = true
|
91
|
+
@output_stream.flush
|
87
92
|
@output_stream
|
88
93
|
end
|
89
94
|
|
90
95
|
# Closes the current entry and opens a new for writing.
|
91
96
|
# +entry+ can be a ZipEntry object or a string.
|
92
|
-
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
|
+
)
|
93
101
|
raise Error, 'zip stream is closed' if @closed
|
94
102
|
|
95
|
-
new_entry =
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
init_next_entry(new_entry
|
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)
|
106
114
|
@current_entry = new_entry
|
107
115
|
end
|
108
116
|
|
@@ -112,7 +120,7 @@ module Zip
|
|
112
120
|
raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
|
113
121
|
|
114
122
|
finalize_current_entry
|
115
|
-
@
|
123
|
+
@cdir << entry
|
116
124
|
src_pos = entry.local_header_offset
|
117
125
|
entry.write_local_entry(@output_stream)
|
118
126
|
@compressor = NullCompressor.instance
|
@@ -136,47 +144,45 @@ module Zip
|
|
136
144
|
@current_entry.calculate_local_header_size
|
137
145
|
@current_entry.size = @compressor.size
|
138
146
|
@current_entry.crc = @compressor.crc
|
139
|
-
@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
|
+
)
|
140
152
|
@current_entry.gp_flags |= @encrypter.gp_flags
|
141
153
|
@current_entry = nil
|
142
154
|
@compressor = ::Zip::NullCompressor.instance
|
143
155
|
end
|
144
156
|
|
145
|
-
def init_next_entry(entry
|
157
|
+
def init_next_entry(entry)
|
146
158
|
finalize_current_entry
|
147
|
-
@
|
159
|
+
@cdir << entry
|
148
160
|
entry.write_local_entry(@output_stream)
|
149
161
|
@encrypter.reset!
|
150
162
|
@output_stream << @encrypter.header(entry.mtime)
|
151
|
-
@compressor = get_compressor(entry
|
163
|
+
@compressor = get_compressor(entry)
|
152
164
|
end
|
153
165
|
|
154
|
-
def get_compressor(entry
|
166
|
+
def get_compressor(entry)
|
155
167
|
case entry.compression_method
|
156
168
|
when Entry::DEFLATED
|
157
|
-
::Zip::Deflater.new(@output_stream,
|
169
|
+
::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
|
158
170
|
when Entry::STORED
|
159
171
|
::Zip::PassThruCompressor.new(@output_stream)
|
160
172
|
else
|
161
|
-
raise ::Zip::CompressionMethodError,
|
162
|
-
"Invalid compression method: '#{entry.compression_method}'"
|
173
|
+
raise ::Zip::CompressionMethodError, entry.compression_method
|
163
174
|
end
|
164
175
|
end
|
165
176
|
|
166
177
|
def update_local_headers
|
167
178
|
pos = @output_stream.pos
|
168
|
-
@
|
179
|
+
@cdir.each do |entry|
|
169
180
|
@output_stream.pos = entry.local_header_offset
|
170
|
-
entry.write_local_entry(@output_stream, true)
|
181
|
+
entry.write_local_entry(@output_stream, rewrite: true)
|
171
182
|
end
|
172
183
|
@output_stream.pos = pos
|
173
184
|
end
|
174
185
|
|
175
|
-
def write_central_directory
|
176
|
-
cdir = CentralDirectory.new(@entry_set, @comment)
|
177
|
-
cdir.write_to_stream(@output_stream)
|
178
|
-
end
|
179
|
-
|
180
186
|
protected
|
181
187
|
|
182
188
|
def finish
|
@@ -1,11 +1,13 @@
|
|
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(length = nil, outbuf = '')
|
10
|
+
def read(length = nil, outbuf = +'')
|
9
11
|
return (length.nil? || length.zero? ? '' : nil) if eof
|
10
12
|
|
11
13
|
if length.nil? || (@read_so_far + length) > decompressed_size
|
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'
|
@@ -33,26 +35,12 @@ require 'zip/streamable_stream'
|
|
33
35
|
require 'zip/streamable_directory'
|
34
36
|
require 'zip/errors'
|
35
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.
|
36
43
|
module Zip
|
37
|
-
BANNER = [
|
38
|
-
'RubyZip 3.0 is coming!',
|
39
|
-
'**********************',
|
40
|
-
'',
|
41
|
-
'The public API of some Rubyzip classes has been modernized to use named',
|
42
|
-
'parameters for optional arguments. Please check your usage of the',
|
43
|
-
'following classes:',
|
44
|
-
' * `Zip::File`',
|
45
|
-
' * `Zip::Entry`',
|
46
|
-
' * `Zip::InputStream`',
|
47
|
-
' * `Zip::OutputStream`',
|
48
|
-
'',
|
49
|
-
'Please ensure that your Gemfiles and .gemspecs are suitably restrictive',
|
50
|
-
'to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.3.0).',
|
51
|
-
'See https://github.com/rubyzip/rubyzip for details. The Changelog also',
|
52
|
-
'lists other enhancements and bugfixes that have been implemented since',
|
53
|
-
'version 2.3.0.'
|
54
|
-
].freeze
|
55
|
-
|
56
44
|
extend self
|
57
45
|
attr_accessor :unicode_names,
|
58
46
|
:on_exists_proc,
|
@@ -65,18 +53,23 @@ module Zip
|
|
65
53
|
:force_entry_names_encoding,
|
66
54
|
:validate_entry_sizes
|
67
55
|
|
68
|
-
|
69
|
-
|
56
|
+
DEFAULT_RESTORE_OPTIONS = {
|
57
|
+
restore_ownership: false,
|
58
|
+
restore_permissions: true,
|
59
|
+
restore_times: true
|
60
|
+
}.freeze
|
70
61
|
|
62
|
+
def reset!
|
71
63
|
@_ran_once = false
|
72
64
|
@unicode_names = false
|
73
65
|
@on_exists_proc = false
|
74
66
|
@continue_on_exists_proc = false
|
75
67
|
@sort_entries = false
|
76
68
|
@default_compression = ::Zlib::DEFAULT_COMPRESSION
|
77
|
-
@write_zip64_support =
|
69
|
+
@write_zip64_support = true
|
78
70
|
@warn_invalid_date = true
|
79
71
|
@case_insensitive_match = false
|
72
|
+
@force_entry_names_encoding = nil
|
80
73
|
@validate_entry_sizes = true
|
81
74
|
end
|
82
75
|
|
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,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
|
|
@@ -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')
|