rubyzip 2.4.1 → 3.0.0.rc1
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 +419 -0
- data/LICENSE.md +24 -0
- data/README.md +137 -37
- data/Rakefile +11 -7
- data/lib/zip/central_directory.rb +169 -123
- data/lib/zip/compressor.rb +3 -1
- data/lib/zip/constants.rb +29 -21
- data/lib/zip/crypto/decrypted_io.rb +4 -2
- data/lib/zip/crypto/encryption.rb +4 -2
- data/lib/zip/crypto/null_encryption.rb +6 -4
- data/lib/zip/crypto/traditional_encryption.rb +8 -6
- 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 +43 -4
- data/lib/zip/entry.rb +333 -242
- data/lib/zip/entry_set.rb +11 -9
- data/lib/zip/errors.rb +136 -16
- data/lib/zip/extra_field/generic.rb +6 -13
- data/lib/zip/extra_field/ntfs.rb +6 -4
- 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 +16 -22
- data/lib/zip/file.rb +166 -264
- 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 +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 +27 -596
- data/lib/zip/inflater.rb +7 -5
- data/lib/zip/input_stream.rb +50 -50
- data/lib/zip/ioextras/abstract_input_stream.rb +16 -11
- 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 +3 -1
- data/lib/zip/null_input_stream.rb +3 -1
- data/lib/zip/output_stream.rb +55 -56
- 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 +18 -22
- 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 +4 -2
- data/samples/qtzip.rb +6 -5
- data/samples/write_simple.rb +2 -1
- data/samples/zipfind.rb +1 -0
- metadata +87 -51
- data/TODO +0 -15
- data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
data/lib/zip/input_stream.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
1
4
|
module Zip
|
2
5
|
# InputStream is the basic class for reading zip entries in a
|
3
6
|
# zip file. It is possible to create a InputStream object directly,
|
@@ -37,9 +40,8 @@ module Zip
|
|
37
40
|
#
|
38
41
|
# java.util.zip.ZipInputStream is the original inspiration for this
|
39
42
|
# class.
|
40
|
-
|
41
43
|
class InputStream
|
42
|
-
CHUNK_SIZE = 32_768
|
44
|
+
CHUNK_SIZE = 32_768 # :nodoc:
|
43
45
|
|
44
46
|
include ::Zip::IOExtras::AbstractInputStream
|
45
47
|
|
@@ -49,34 +51,35 @@ 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,
|
54
|
+
def initialize(context, offset: 0, decrypter: nil)
|
53
55
|
super()
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
offset = dep_offset if offset.zero?
|
60
|
-
@archive_io = get_io(context, offset)
|
61
|
-
@decompressor = ::Zip::NullDecompressor
|
62
|
-
@decrypter = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
|
56
|
+
@archive_io = get_io(context, offset)
|
57
|
+
@decompressor = ::Zip::NullDecompressor
|
58
|
+
@decrypter = decrypter || ::Zip::NullDecrypter.new
|
63
59
|
@current_entry = nil
|
60
|
+
@complete_entry = nil
|
64
61
|
end
|
65
62
|
|
63
|
+
# Close this InputStream. All further IO will raise an IOError.
|
66
64
|
def close
|
67
65
|
@archive_io.close
|
68
66
|
end
|
69
67
|
|
70
|
-
# Returns
|
71
|
-
# method on a newly created
|
72
|
-
# the first entry in the archive.
|
73
|
-
# no more entries.
|
68
|
+
# Returns an Entry object and positions the stream at the beginning of
|
69
|
+
# the entry data. It is necessary to call this method on a newly created
|
70
|
+
# InputStream before reading from the first entry in the archive.
|
71
|
+
# Returns nil when there are no more entries.
|
74
72
|
def get_next_entry
|
75
|
-
@
|
73
|
+
unless @current_entry.nil?
|
74
|
+
raise StreamingError, @current_entry if @current_entry.incomplete?
|
75
|
+
|
76
|
+
@archive_io.seek(@current_entry.next_header_offset, IO::SEEK_SET)
|
77
|
+
end
|
78
|
+
|
76
79
|
open_entry
|
77
80
|
end
|
78
81
|
|
79
|
-
# Rewinds the stream to the beginning of the current entry
|
82
|
+
# Rewinds the stream to the beginning of the current entry.
|
80
83
|
def rewind
|
81
84
|
return if @current_entry.nil?
|
82
85
|
|
@@ -91,18 +94,19 @@ module Zip
|
|
91
94
|
@decompressor.read(length, outbuf)
|
92
95
|
end
|
93
96
|
|
97
|
+
# Returns the size of the current entry, or `nil` if there isn't one.
|
98
|
+
def size
|
99
|
+
return if @current_entry.nil?
|
100
|
+
|
101
|
+
@current_entry.size
|
102
|
+
end
|
103
|
+
|
94
104
|
class << self
|
95
105
|
# Same as #initialize but if a block is passed the opened
|
96
106
|
# stream is passed to the block and closed when the block
|
97
107
|
# returns.
|
98
|
-
def open(filename_or_io,
|
99
|
-
|
100
|
-
Zip.warn_about_v3_api('Zip::InputStream.new')
|
101
|
-
end
|
102
|
-
|
103
|
-
offset = dep_offset if offset.zero?
|
104
|
-
|
105
|
-
zio = new(filename_or_io, offset: offset, decrypter: decrypter || dep_decrypter)
|
108
|
+
def open(filename_or_io, offset: 0, decrypter: nil)
|
109
|
+
zio = new(filename_or_io, offset: offset, decrypter: decrypter)
|
106
110
|
return zio unless block_given?
|
107
111
|
|
108
112
|
begin
|
@@ -111,17 +115,11 @@ module Zip
|
|
111
115
|
zio.close if zio
|
112
116
|
end
|
113
117
|
end
|
114
|
-
|
115
|
-
def open_buffer(filename_or_io, offset = 0)
|
116
|
-
Zip.warn_about_v3_api('Zip::InputStream.open_buffer')
|
117
|
-
|
118
|
-
::Zip::InputStream.open(filename_or_io, offset)
|
119
|
-
end
|
120
118
|
end
|
121
119
|
|
122
120
|
protected
|
123
121
|
|
124
|
-
def get_io(io_or_file, offset = 0)
|
122
|
+
def get_io(io_or_file, offset = 0) # :nodoc:
|
125
123
|
if io_or_file.respond_to?(:seek)
|
126
124
|
io = io_or_file.dup
|
127
125
|
io.seek(offset, ::IO::SEEK_SET)
|
@@ -133,56 +131,58 @@ module Zip
|
|
133
131
|
end
|
134
132
|
end
|
135
133
|
|
136
|
-
def open_entry
|
134
|
+
def open_entry # :nodoc:
|
137
135
|
@current_entry = ::Zip::Entry.read_local_entry(@archive_io)
|
138
|
-
if @current_entry
|
139
|
-
|
136
|
+
return if @current_entry.nil?
|
137
|
+
|
138
|
+
if @current_entry.encrypted? && @decrypter.kind_of?(NullDecrypter)
|
139
|
+
raise Error,
|
140
|
+
'A password is required to decode this zip file'
|
140
141
|
end
|
141
142
|
|
142
|
-
if @current_entry
|
143
|
-
|
144
|
-
&& @current_entry.size == 0 && !@complete_entry
|
145
|
-
raise GPFBit3Error,
|
146
|
-
'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
|
147
|
-
'Please use ::Zip::File instead of ::Zip::InputStream'
|
143
|
+
if @current_entry.incomplete? && @current_entry.compressed_size == 0 && !@complete_entry
|
144
|
+
raise StreamingError, @current_entry
|
148
145
|
end
|
146
|
+
|
149
147
|
@decrypted_io = get_decrypted_io
|
150
148
|
@decompressor = get_decompressor
|
151
149
|
flush
|
152
150
|
@current_entry
|
153
151
|
end
|
154
152
|
|
155
|
-
def get_decrypted_io
|
153
|
+
def get_decrypted_io # :nodoc:
|
156
154
|
header = @archive_io.read(@decrypter.header_bytesize)
|
157
155
|
@decrypter.reset!(header)
|
158
156
|
|
159
157
|
::Zip::DecryptedIo.new(@archive_io, @decrypter)
|
160
158
|
end
|
161
159
|
|
162
|
-
def get_decompressor
|
160
|
+
def get_decompressor # :nodoc:
|
163
161
|
return ::Zip::NullDecompressor if @current_entry.nil?
|
164
162
|
|
165
163
|
decompressed_size =
|
166
|
-
if @current_entry.incomplete? && @current_entry.crc == 0 &&
|
164
|
+
if @current_entry.incomplete? && @current_entry.crc == 0 &&
|
165
|
+
@current_entry.size == 0 && @complete_entry
|
167
166
|
@complete_entry.size
|
168
167
|
else
|
169
168
|
@current_entry.size
|
170
169
|
end
|
171
170
|
|
172
|
-
decompressor_class = ::Zip::Decompressor.find_by_compression_method(
|
171
|
+
decompressor_class = ::Zip::Decompressor.find_by_compression_method(
|
172
|
+
@current_entry.compression_method
|
173
|
+
)
|
173
174
|
if decompressor_class.nil?
|
174
|
-
raise ::Zip::CompressionMethodError,
|
175
|
-
"Unsupported compression method #{@current_entry.compression_method}"
|
175
|
+
raise ::Zip::CompressionMethodError, @current_entry.compression_method
|
176
176
|
end
|
177
177
|
|
178
178
|
decompressor_class.new(@decrypted_io, decompressed_size)
|
179
179
|
end
|
180
180
|
|
181
|
-
def produce_input
|
181
|
+
def produce_input # :nodoc:
|
182
182
|
@decompressor.read(CHUNK_SIZE)
|
183
183
|
end
|
184
184
|
|
185
|
-
def input_finished?
|
185
|
+
def input_finished? # :nodoc:
|
186
186
|
@decompressor.eof
|
187
187
|
end
|
188
188
|
end
|
@@ -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,22 +13,22 @@ 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
|
26
28
|
rbuf = sysread(number_of_bytes, buf)
|
27
29
|
out = @output_buffer
|
28
30
|
out << rbuf if rbuf
|
29
|
-
@output_buffer = ''
|
31
|
+
@output_buffer = ''
|
30
32
|
out
|
31
33
|
end
|
32
34
|
else
|
@@ -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
|
@@ -74,15 +76,18 @@ module Zip
|
|
74
76
|
a_sep_string = "#{$INPUT_RECORD_SEPARATOR}#{$INPUT_RECORD_SEPARATOR}" if a_sep_string.empty?
|
75
77
|
|
76
78
|
buffer_index = 0
|
77
|
-
over_limit =
|
79
|
+
over_limit = number_of_bytes && @output_buffer.bytesize >= number_of_bytes
|
78
80
|
while (match_index = @output_buffer.index(a_sep_string, buffer_index)).nil? && !over_limit
|
79
81
|
buffer_index = [buffer_index, @output_buffer.bytesize - a_sep_string.bytesize].max
|
80
82
|
return @output_buffer.empty? ? nil : flush if input_finished?
|
81
83
|
|
82
84
|
@output_buffer << produce_input
|
83
|
-
over_limit =
|
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, ''
|
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
|
-
tr = toread
|
16
|
-
ostream.write(istream.read(tr, ''
|
15
|
+
tr = [toread, CHUNK_SIZE].min
|
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,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,49 @@ 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,
|
32
|
+
def initialize(file_name, stream: false, encrypter: nil)
|
28
33
|
super()
|
29
|
-
|
30
|
-
Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
|
31
|
-
|
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
|
44
46
|
@closed = false
|
45
47
|
@current_entry = nil
|
46
|
-
@comment = nil
|
47
48
|
end
|
48
49
|
|
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
50
|
class << self
|
53
|
-
|
51
|
+
# Same as #initialize but if a block is passed the opened
|
52
|
+
# stream is passed to the block and closed when the block
|
53
|
+
# returns.
|
54
|
+
def open(file_name, encrypter: nil)
|
54
55
|
return new(file_name) unless block_given?
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
zos = new(file_name, stream: false, encrypter: (encrypter || dep_encrypter))
|
57
|
+
zos = new(file_name, stream: false, encrypter: encrypter)
|
59
58
|
yield zos
|
60
59
|
ensure
|
61
60
|
zos.close if zos
|
62
61
|
end
|
63
62
|
|
64
63
|
# 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
|
-
|
64
|
+
def write_buffer(io = ::StringIO.new, encrypter: nil)
|
68
65
|
io.binmode if io.respond_to?(:binmode)
|
69
|
-
zos = new(io, stream: true, encrypter:
|
66
|
+
zos = new(io, stream: true, encrypter: encrypter)
|
70
67
|
yield zos
|
71
68
|
zos.close_buffer
|
72
69
|
end
|
@@ -78,7 +75,7 @@ module Zip
|
|
78
75
|
|
79
76
|
finalize_current_entry
|
80
77
|
update_local_headers
|
81
|
-
|
78
|
+
@cdir.write_to_stream(@output_stream)
|
82
79
|
@output_stream.close
|
83
80
|
@closed = true
|
84
81
|
end
|
@@ -89,37 +86,41 @@ module Zip
|
|
89
86
|
|
90
87
|
finalize_current_entry
|
91
88
|
update_local_headers
|
92
|
-
|
89
|
+
@cdir.write_to_stream(@output_stream)
|
93
90
|
@closed = true
|
91
|
+
@output_stream.flush
|
94
92
|
@output_stream
|
95
93
|
end
|
96
94
|
|
97
95
|
# Closes the current entry and opens a new for writing.
|
98
96
|
# +entry+ can be a ZipEntry object or a string.
|
99
|
-
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
|
+
)
|
100
101
|
raise Error, 'zip stream is closed' if @closed
|
101
102
|
|
102
|
-
new_entry =
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
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)
|
113
114
|
@current_entry = new_entry
|
114
115
|
end
|
115
116
|
|
116
|
-
def copy_raw_entry(entry)
|
117
|
+
def copy_raw_entry(entry) # :nodoc:
|
117
118
|
entry = entry.dup
|
118
119
|
raise Error, 'zip stream is closed' if @closed
|
119
120
|
raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
|
120
121
|
|
121
122
|
finalize_current_entry
|
122
|
-
@
|
123
|
+
@cdir << entry
|
123
124
|
src_pos = entry.local_header_offset
|
124
125
|
entry.write_local_entry(@output_stream)
|
125
126
|
@compressor = NullCompressor.instance
|
@@ -138,55 +139,53 @@ module Zip
|
|
138
139
|
return unless @current_entry
|
139
140
|
|
140
141
|
finish
|
141
|
-
@current_entry.compressed_size = @output_stream.tell -
|
142
|
-
@current_entry.local_header_offset -
|
142
|
+
@current_entry.compressed_size = @output_stream.tell -
|
143
|
+
@current_entry.local_header_offset -
|
143
144
|
@current_entry.calculate_local_header_size
|
144
145
|
@current_entry.size = @compressor.size
|
145
146
|
@current_entry.crc = @compressor.crc
|
146
|
-
@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
|
+
)
|
147
152
|
@current_entry.gp_flags |= @encrypter.gp_flags
|
148
153
|
@current_entry = nil
|
149
154
|
@compressor = ::Zip::NullCompressor.instance
|
150
155
|
end
|
151
156
|
|
152
|
-
def init_next_entry(entry
|
157
|
+
def init_next_entry(entry)
|
153
158
|
finalize_current_entry
|
154
|
-
@
|
159
|
+
@cdir << entry
|
155
160
|
entry.write_local_entry(@output_stream)
|
156
161
|
@encrypter.reset!
|
157
162
|
@output_stream << @encrypter.header(entry.mtime)
|
158
|
-
@compressor = get_compressor(entry
|
163
|
+
@compressor = get_compressor(entry)
|
159
164
|
end
|
160
165
|
|
161
|
-
def get_compressor(entry
|
166
|
+
def get_compressor(entry)
|
162
167
|
case entry.compression_method
|
163
168
|
when Entry::DEFLATED
|
164
|
-
::Zip::Deflater.new(@output_stream,
|
169
|
+
::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
|
165
170
|
when Entry::STORED
|
166
171
|
::Zip::PassThruCompressor.new(@output_stream)
|
167
172
|
else
|
168
|
-
raise ::Zip::CompressionMethodError,
|
169
|
-
"Invalid compression method: '#{entry.compression_method}'"
|
173
|
+
raise ::Zip::CompressionMethodError, entry.compression_method
|
170
174
|
end
|
171
175
|
end
|
172
176
|
|
173
177
|
def update_local_headers
|
174
178
|
pos = @output_stream.pos
|
175
|
-
@
|
179
|
+
@cdir.each do |entry|
|
176
180
|
@output_stream.pos = entry.local_header_offset
|
177
|
-
entry.write_local_entry(@output_stream, true)
|
181
|
+
entry.write_local_entry(@output_stream, rewrite: true)
|
178
182
|
end
|
179
183
|
@output_stream.pos = pos
|
180
184
|
end
|
181
185
|
|
182
|
-
def write_central_directory
|
183
|
-
cdir = CentralDirectory.new(@entry_set, @comment)
|
184
|
-
cdir.write_to_stream(@output_stream)
|
185
|
-
end
|
186
|
-
|
187
186
|
protected
|
188
187
|
|
189
|
-
def finish
|
188
|
+
def finish # :nodoc:
|
190
189
|
@compressor.finish
|
191
190
|
end
|
192
191
|
|
@@ -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