rubyzip 2.4.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 +112 -37
- 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 +32 -3
- data/lib/zip/entry.rb +262 -198
- 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 +144 -265
- 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 +7 -5
- data/lib/zip/input_stream.rb +44 -39
- data/lib/zip/ioextras/abstract_input_stream.rb +14 -9
- 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 +47 -48
- 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 -20
- 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 +84 -50
- data/TODO +0 -15
- data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
data/Rakefile
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bundler/gem_tasks'
|
2
4
|
require 'rake/testtask'
|
5
|
+
require 'rdoc/task'
|
3
6
|
require 'rubocop/rake_task'
|
4
7
|
|
5
8
|
task default: :test
|
@@ -11,11 +14,12 @@ Rake::TestTask.new(:test) do |test|
|
|
11
14
|
test.verbose = true
|
12
15
|
end
|
13
16
|
|
14
|
-
|
17
|
+
RDoc::Task.new do |rdoc|
|
18
|
+
rdoc.main = 'README.md'
|
19
|
+
rdoc.rdoc_files.include('README.md', 'lib/**/*.rb')
|
20
|
+
rdoc.options << '--markup=markdown'
|
21
|
+
rdoc.options << '--tab-width=2'
|
22
|
+
rdoc.options << "-t Rubyzip version #{::Zip::VERSION}"
|
23
|
+
end
|
15
24
|
|
16
|
-
|
17
|
-
# test.libs << File.join(File.dirname(__FILE__), 'lib')
|
18
|
-
# test.libs << File.join(File.dirname(__FILE__), 'test')
|
19
|
-
# test.pattern = File.join(File.dirname(__FILE__), 'test/zip64_full_test.rb')
|
20
|
-
# test.verbose = true
|
21
|
-
# end
|
25
|
+
RuboCop::RakeTask.new
|
@@ -1,45 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
require_relative 'dirtyable'
|
6
|
+
|
1
7
|
module Zip
|
2
|
-
class CentralDirectory
|
3
|
-
|
8
|
+
class CentralDirectory # :nodoc:
|
9
|
+
extend Forwardable
|
10
|
+
include Dirtyable
|
11
|
+
|
12
|
+
END_OF_CD_SIG = 0x06054b50
|
13
|
+
ZIP64_END_OF_CD_SIG = 0x06064b50
|
14
|
+
ZIP64_EOCD_LOCATOR_SIG = 0x07064b50
|
4
15
|
|
5
|
-
END_OF_CDS = 0x06054b50
|
6
|
-
ZIP64_END_OF_CDS = 0x06064b50
|
7
|
-
ZIP64_EOCD_LOCATOR = 0x07064b50
|
8
|
-
MAX_END_OF_CDS_SIZE = 65_536 + 18
|
9
16
|
STATIC_EOCD_SIZE = 22
|
17
|
+
ZIP64_STATIC_EOCD_SIZE = 56
|
18
|
+
ZIP64_EOCD_LOC_SIZE = 20
|
19
|
+
MAX_FILE_COMMENT_SIZE = (1 << 16) - 1
|
20
|
+
MAX_END_OF_CD_SIZE =
|
21
|
+
MAX_FILE_COMMENT_SIZE + STATIC_EOCD_SIZE + ZIP64_EOCD_LOC_SIZE
|
10
22
|
|
11
|
-
|
23
|
+
attr_accessor :comment
|
12
24
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
25
|
+
def_delegators :@entry_set,
|
26
|
+
:<<, :delete, :each, :entries, :find_entry, :glob,
|
27
|
+
:include?, :size
|
28
|
+
|
29
|
+
mark_dirty :<<, :comment=, :delete
|
17
30
|
|
18
31
|
def initialize(entries = EntrySet.new, comment = '') #:nodoc:
|
19
|
-
super()
|
32
|
+
super(dirty_on_create: false)
|
20
33
|
@entry_set = entries.kind_of?(EntrySet) ? entries : EntrySet.new(entries)
|
21
34
|
@comment = comment
|
22
35
|
end
|
23
36
|
|
37
|
+
def read_from_stream(io)
|
38
|
+
read_eocds(io)
|
39
|
+
read_central_directory_entries(io)
|
40
|
+
end
|
41
|
+
|
24
42
|
def write_to_stream(io) #:nodoc:
|
25
43
|
cdir_offset = io.tell
|
26
44
|
@entry_set.each { |entry| entry.write_c_dir_entry(io) }
|
27
45
|
eocd_offset = io.tell
|
28
46
|
cdir_size = eocd_offset - cdir_offset
|
29
|
-
if
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
write_64_e_o_c_d(io, cdir_offset, cdir_size)
|
34
|
-
write_64_eocd_locator(io, eocd_offset)
|
35
|
-
end
|
47
|
+
if Zip.write_zip64_support &&
|
48
|
+
(cdir_offset > 0xFFFFFFFF || cdir_size > 0xFFFFFFFF || @entry_set.size > 0xFFFF)
|
49
|
+
write_64_e_o_c_d(io, cdir_offset, cdir_size)
|
50
|
+
write_64_eocd_locator(io, eocd_offset)
|
36
51
|
end
|
37
52
|
write_e_o_c_d(io, cdir_offset, cdir_size)
|
38
53
|
end
|
39
54
|
|
55
|
+
# Reads the End of Central Directory Record (and the Zip64 equivalent if
|
56
|
+
# needs be) and returns the number of entries in the archive. This is a
|
57
|
+
# convenience method that avoids reading in all of the entry data to get a
|
58
|
+
# very quick entry count.
|
59
|
+
def count_entries(io)
|
60
|
+
read_eocds(io)
|
61
|
+
@size
|
62
|
+
end
|
63
|
+
|
64
|
+
def ==(other) #:nodoc:
|
65
|
+
return false unless other.kind_of?(CentralDirectory)
|
66
|
+
|
67
|
+
@entry_set.entries.sort == other.entries.sort && comment == other.comment
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
40
72
|
def write_e_o_c_d(io, offset, cdir_size) #:nodoc:
|
41
73
|
tmp = [
|
42
|
-
|
74
|
+
END_OF_CD_SIG,
|
43
75
|
0, # @numberOfThisDisk
|
44
76
|
0, # @numberOfDiskWithStartOfCDir
|
45
77
|
@entry_set ? [@entry_set.size, 0xFFFF].min : 0,
|
@@ -52,11 +84,9 @@ module Zip
|
|
52
84
|
io << @comment
|
53
85
|
end
|
54
86
|
|
55
|
-
private :write_e_o_c_d
|
56
|
-
|
57
87
|
def write_64_e_o_c_d(io, offset, cdir_size) #:nodoc:
|
58
88
|
tmp = [
|
59
|
-
|
89
|
+
ZIP64_END_OF_CD_SIG,
|
60
90
|
44, # size of zip64 end of central directory record (excludes signature and field itself)
|
61
91
|
VERSION_MADE_BY,
|
62
92
|
VERSION_NEEDED_TO_EXTRACT_ZIP64,
|
@@ -70,11 +100,9 @@ module Zip
|
|
70
100
|
io << tmp.pack('VQ<vvVVQ<Q<Q<Q<')
|
71
101
|
end
|
72
102
|
|
73
|
-
private :write_64_e_o_c_d
|
74
|
-
|
75
103
|
def write_64_eocd_locator(io, zip64_eocd_offset)
|
76
104
|
tmp = [
|
77
|
-
|
105
|
+
ZIP64_EOCD_LOCATOR_SIG,
|
78
106
|
0, # number of disk containing the start of zip64 eocd record
|
79
107
|
zip64_eocd_offset, # offset of the start of zip64 eocd record in its disk
|
80
108
|
1 # total number of disks
|
@@ -82,127 +110,145 @@ module Zip
|
|
82
110
|
io << tmp.pack('VVQ<V')
|
83
111
|
end
|
84
112
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
@
|
90
|
-
@
|
91
|
-
@
|
92
|
-
@
|
93
|
-
@
|
94
|
-
@
|
95
|
-
@
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
113
|
+
def unpack_64_e_o_c_d(buffer) #:nodoc:
|
114
|
+
_, # ZIP64_END_OF_CD_SIG. We know we have this at this point.
|
115
|
+
@size_of_zip64_e_o_c_d,
|
116
|
+
@version_made_by,
|
117
|
+
@version_needed_for_extract,
|
118
|
+
@number_of_this_disk,
|
119
|
+
@number_of_disk_with_start_of_cdir,
|
120
|
+
@total_number_of_entries_in_cdir_on_this_disk,
|
121
|
+
@size,
|
122
|
+
@size_in_bytes,
|
123
|
+
@cdir_offset = buffer.unpack('VQ<vvVVQ<Q<Q<Q<')
|
124
|
+
|
125
|
+
zip64_extensible_data_size =
|
126
|
+
@size_of_zip64_e_o_c_d - ZIP64_STATIC_EOCD_SIZE + 12
|
127
|
+
@zip64_extensible_data = if zip64_extensible_data_size.zero?
|
128
|
+
''
|
129
|
+
else
|
130
|
+
buffer.slice(
|
131
|
+
ZIP64_STATIC_EOCD_SIZE,
|
132
|
+
zip64_extensible_data_size
|
133
|
+
)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def unpack_64_eocd_locator(buffer) #:nodoc:
|
138
|
+
_, # ZIP64_EOCD_LOCATOR_SIG. We know we have this at this point.
|
139
|
+
_, zip64_eocd_offset, = buffer.unpack('VVQ<V')
|
140
|
+
|
141
|
+
zip64_eocd_offset
|
100
142
|
end
|
101
143
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
comment_length
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
144
|
+
def unpack_e_o_c_d(buffer) #:nodoc:
|
145
|
+
_, # END_OF_CD_SIG. We know we have this at this point.
|
146
|
+
num_disk,
|
147
|
+
num_disk_cdir,
|
148
|
+
num_cdir_disk,
|
149
|
+
num_entries,
|
150
|
+
size_in_bytes,
|
151
|
+
cdir_offset,
|
152
|
+
comment_length = buffer.unpack('VvvvvVVv')
|
153
|
+
|
154
|
+
@number_of_this_disk = num_disk unless num_disk == 0xFFFF
|
155
|
+
@number_of_disk_with_start_of_cdir = num_disk_cdir unless num_disk_cdir == 0xFFFF
|
156
|
+
@total_number_of_entries_in_cdir_on_this_disk = num_cdir_disk unless num_cdir_disk == 0xFFFF
|
157
|
+
@size = num_entries unless num_entries == 0xFFFF
|
158
|
+
@size_in_bytes = size_in_bytes unless size_in_bytes == 0xFFFFFFFF
|
159
|
+
@cdir_offset = cdir_offset unless cdir_offset == 0xFFFFFFFF
|
160
|
+
|
161
|
+
@comment = if comment_length.positive?
|
162
|
+
buffer.slice(STATIC_EOCD_SIZE, comment_length)
|
163
|
+
else
|
164
|
+
''
|
165
|
+
end
|
117
166
|
end
|
118
167
|
|
119
168
|
def read_central_directory_entries(io) #:nodoc:
|
169
|
+
# `StringIO` doesn't raise `EINVAL` if you seek beyond the current end,
|
170
|
+
# so we need to catch that *and* query `io#eof?` here.
|
171
|
+
eof = false
|
120
172
|
begin
|
121
173
|
io.seek(@cdir_offset, IO::SEEK_SET)
|
122
174
|
rescue Errno::EINVAL
|
123
|
-
|
175
|
+
eof = true
|
124
176
|
end
|
177
|
+
raise Error, 'Zip consistency problem while reading central directory entry' if eof || io.eof?
|
178
|
+
|
125
179
|
@entry_set = EntrySet.new
|
126
180
|
@size.times do
|
127
|
-
|
128
|
-
|
129
|
-
|
181
|
+
entry = Entry.read_c_dir_entry(io)
|
182
|
+
next unless entry
|
183
|
+
|
184
|
+
offset = if entry.zip64?
|
185
|
+
entry.extra['Zip64'].relative_header_offset
|
186
|
+
else
|
187
|
+
entry.local_header_offset
|
188
|
+
end
|
189
|
+
|
190
|
+
unless offset.nil?
|
191
|
+
io_save = io.tell
|
192
|
+
io.seek(offset, IO::SEEK_SET)
|
193
|
+
entry.read_extra_field(read_local_extra_field(io), local: true)
|
194
|
+
io.seek(io_save, IO::SEEK_SET)
|
195
|
+
end
|
130
196
|
|
131
|
-
|
132
|
-
buf = start_buf(io)
|
133
|
-
if zip64_file?(buf)
|
134
|
-
read_64_e_o_c_d(buf)
|
135
|
-
else
|
136
|
-
read_e_o_c_d(buf)
|
197
|
+
@entry_set << entry
|
137
198
|
end
|
138
|
-
read_central_directory_entries(io)
|
139
199
|
end
|
140
200
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
201
|
+
def read_local_extra_field(io)
|
202
|
+
buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
|
203
|
+
return '' unless buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
|
144
204
|
|
145
|
-
|
205
|
+
head, _, _, _, _, _, _, _, _, _, n_len, e_len = buf.unpack('VCCvvvvVVVvv')
|
206
|
+
return '' unless head == ::Zip::LOCAL_ENTRY_SIGNATURE
|
146
207
|
|
147
|
-
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
buf
|
208
|
+
io.seek(n_len, IO::SEEK_CUR) # Skip over the entry name.
|
209
|
+
io.read(e_len)
|
152
210
|
end
|
153
211
|
|
154
|
-
def
|
155
|
-
|
156
|
-
end
|
212
|
+
def read_eocds(io) #:nodoc:
|
213
|
+
base_location, data = eocd_data(io)
|
157
214
|
|
158
|
-
|
159
|
-
|
160
|
-
io.seek(-MAX_END_OF_CDS_SIZE, IO::SEEK_END)
|
161
|
-
rescue Errno::EINVAL
|
162
|
-
io.seek(0, IO::SEEK_SET)
|
163
|
-
end
|
164
|
-
io.read
|
165
|
-
end
|
215
|
+
eocd_location = data.rindex([END_OF_CD_SIG].pack('V'))
|
216
|
+
raise Error, 'Zip end of central directory signature not found' unless eocd_location
|
166
217
|
|
167
|
-
|
168
|
-
zip_64_start = buf.rindex([ZIP64_END_OF_CDS].pack('V'))
|
169
|
-
raise Error, 'Zip64 end of central directory signature not found' unless zip_64_start
|
218
|
+
zip64_eocd_locator = data.rindex([ZIP64_EOCD_LOCATOR_SIG].pack('V'))
|
170
219
|
|
171
|
-
|
172
|
-
|
220
|
+
if zip64_eocd_locator
|
221
|
+
zip64_eocd_location = data.rindex([ZIP64_END_OF_CD_SIG].pack('V'))
|
173
222
|
|
174
|
-
|
223
|
+
zip64_eocd_data =
|
224
|
+
if zip64_eocd_location
|
225
|
+
data.slice(zip64_eocd_location..zip64_eocd_locator)
|
226
|
+
else
|
227
|
+
zip64_eocd_location = unpack_64_eocd_locator(
|
228
|
+
data.slice(zip64_eocd_locator..eocd_location)
|
229
|
+
)
|
230
|
+
unless zip64_eocd_location
|
231
|
+
raise Error, 'Zip64 end of central directory signature not found'
|
232
|
+
end
|
175
233
|
|
176
|
-
|
177
|
-
|
178
|
-
|
234
|
+
io.seek(zip64_eocd_location, IO::SEEK_SET)
|
235
|
+
io.read(base_location + zip64_eocd_locator - zip64_eocd_location)
|
236
|
+
end
|
179
237
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
# For iterating over the entries.
|
184
|
-
def each(&a_proc)
|
185
|
-
@entry_set.each(&a_proc)
|
186
|
-
end
|
187
|
-
|
188
|
-
# Returns the number of entries in the central directory (and
|
189
|
-
# consequently in the zip archive).
|
190
|
-
def size
|
191
|
-
@entry_set.size
|
192
|
-
end
|
238
|
+
unpack_64_e_o_c_d(zip64_eocd_data)
|
239
|
+
end
|
193
240
|
|
194
|
-
|
195
|
-
cdir = new
|
196
|
-
cdir.read_from_stream(io)
|
197
|
-
cdir
|
198
|
-
rescue Error
|
199
|
-
nil
|
241
|
+
unpack_e_o_c_d(data.slice(eocd_location..-1))
|
200
242
|
end
|
201
243
|
|
202
|
-
def
|
203
|
-
|
244
|
+
def eocd_data(io)
|
245
|
+
begin
|
246
|
+
io.seek(-MAX_END_OF_CD_SIZE, IO::SEEK_END)
|
247
|
+
rescue Errno::EINVAL
|
248
|
+
io.seek(0, IO::SEEK_SET)
|
249
|
+
end
|
204
250
|
|
205
|
-
|
251
|
+
[io.tell, io.read]
|
206
252
|
end
|
207
253
|
end
|
208
254
|
end
|
data/lib/zip/compressor.rb
CHANGED
data/lib/zip/constants.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
4
|
RUNNING_ON_WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/i
|
3
5
|
|
@@ -11,6 +13,8 @@ module Zip
|
|
11
13
|
VERSION_NEEDED_TO_EXTRACT = 20
|
12
14
|
VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45
|
13
15
|
|
16
|
+
SPLIT_FILE_SIGNATURE = 0x08074b50
|
17
|
+
|
14
18
|
FILE_TYPE_FILE = 0o10
|
15
19
|
FILE_TYPE_DIR = 0o04
|
16
20
|
FILE_TYPE_SYMLINK = 0o12
|
@@ -38,27 +42,27 @@ module Zip
|
|
38
42
|
FSTYPE_ATHEOS = 30
|
39
43
|
|
40
44
|
FSTYPES = {
|
41
|
-
FSTYPE_FAT => 'FAT'
|
42
|
-
FSTYPE_AMIGA => 'Amiga'
|
43
|
-
FSTYPE_VMS => 'VMS (Vax or Alpha AXP)'
|
44
|
-
FSTYPE_UNIX => 'Unix'
|
45
|
-
FSTYPE_VM_CMS => 'VM/CMS'
|
46
|
-
FSTYPE_ATARI => 'Atari ST'
|
47
|
-
FSTYPE_HPFS => 'OS/2 or NT HPFS'
|
48
|
-
FSTYPE_MAC => 'Macintosh'
|
49
|
-
FSTYPE_Z_SYSTEM => 'Z-System'
|
50
|
-
FSTYPE_CPM => 'CP/M'
|
51
|
-
FSTYPE_TOPS20 => 'TOPS-20'
|
52
|
-
FSTYPE_NTFS => 'NTFS'
|
53
|
-
FSTYPE_QDOS => 'SMS/QDOS'
|
54
|
-
FSTYPE_ACORN => 'Acorn RISC OS'
|
55
|
-
FSTYPE_VFAT => 'Win32 VFAT'
|
56
|
-
FSTYPE_MVS => 'MVS'
|
57
|
-
FSTYPE_BEOS => 'BeOS'
|
58
|
-
FSTYPE_TANDEM => 'Tandem NSK'
|
59
|
-
FSTYPE_THEOS => 'Theos'
|
60
|
-
FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'
|
61
|
-
FSTYPE_ATHEOS => 'AtheOS'
|
45
|
+
FSTYPE_FAT => 'FAT',
|
46
|
+
FSTYPE_AMIGA => 'Amiga',
|
47
|
+
FSTYPE_VMS => 'VMS (Vax or Alpha AXP)',
|
48
|
+
FSTYPE_UNIX => 'Unix',
|
49
|
+
FSTYPE_VM_CMS => 'VM/CMS',
|
50
|
+
FSTYPE_ATARI => 'Atari ST',
|
51
|
+
FSTYPE_HPFS => 'OS/2 or NT HPFS',
|
52
|
+
FSTYPE_MAC => 'Macintosh',
|
53
|
+
FSTYPE_Z_SYSTEM => 'Z-System',
|
54
|
+
FSTYPE_CPM => 'CP/M',
|
55
|
+
FSTYPE_TOPS20 => 'TOPS-20',
|
56
|
+
FSTYPE_NTFS => 'NTFS',
|
57
|
+
FSTYPE_QDOS => 'SMS/QDOS',
|
58
|
+
FSTYPE_ACORN => 'Acorn RISC OS',
|
59
|
+
FSTYPE_VFAT => 'Win32 VFAT',
|
60
|
+
FSTYPE_MVS => 'MVS',
|
61
|
+
FSTYPE_BEOS => 'BeOS',
|
62
|
+
FSTYPE_TANDEM => 'Tandem NSK',
|
63
|
+
FSTYPE_THEOS => 'Theos',
|
64
|
+
FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)',
|
65
|
+
FSTYPE_ATHEOS => 'AtheOS'
|
62
66
|
}.freeze
|
63
67
|
|
64
68
|
COMPRESSION_METHOD_STORE = 0
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
module NullEncryption
|
4
|
+
module NullEncryption # :nodoc:
|
3
5
|
def header_bytesize
|
4
6
|
0
|
5
7
|
end
|
@@ -9,7 +11,7 @@ module Zip
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
|
-
class NullEncrypter < Encrypter
|
14
|
+
class NullEncrypter < Encrypter # :nodoc:
|
13
15
|
include NullEncryption
|
14
16
|
|
15
17
|
def header(_mtime)
|
@@ -27,7 +29,7 @@ module Zip
|
|
27
29
|
def reset!; end
|
28
30
|
end
|
29
31
|
|
30
|
-
class NullDecrypter < Decrypter
|
32
|
+
class NullDecrypter < Decrypter # :nodoc:
|
31
33
|
include NullEncryption
|
32
34
|
|
33
35
|
def decrypt(data)
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
module TraditionalEncryption
|
4
|
+
module TraditionalEncryption # :nodoc:
|
3
5
|
def initialize(password)
|
4
6
|
@password = password
|
5
7
|
reset_keys!
|
@@ -36,7 +38,7 @@ module Zip
|
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
|
-
class TraditionalEncrypter < Encrypter
|
41
|
+
class TraditionalEncrypter < Encrypter # :nodoc:
|
40
42
|
include TraditionalEncryption
|
41
43
|
|
42
44
|
def header(mtime)
|
@@ -70,7 +72,7 @@ module Zip
|
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
|
-
class TraditionalDecrypter < Decrypter
|
75
|
+
class TraditionalDecrypter < Decrypter # :nodoc:
|
74
76
|
include TraditionalEncryption
|
75
77
|
|
76
78
|
def decrypt(data)
|
data/lib/zip/decompressor.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
class Decompressor
|
4
|
+
class Decompressor # :nodoc:all
|
3
5
|
CHUNK_SIZE = 32_768
|
4
6
|
|
5
7
|
def self.decompressor_classes
|
@@ -14,8 +16,7 @@ module Zip
|
|
14
16
|
decompressor_classes[compression_method]
|
15
17
|
end
|
16
18
|
|
17
|
-
attr_reader :input_stream
|
18
|
-
attr_reader :decompressed_size
|
19
|
+
attr_reader :decompressed_size, :input_stream
|
19
20
|
|
20
21
|
def initialize(input_stream, decompressed_size = nil)
|
21
22
|
super()
|
data/lib/zip/deflater.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Zip
|
2
|
-
class Deflater < Compressor
|
4
|
+
class Deflater < Compressor # :nodoc:all
|
3
5
|
def initialize(output_stream, level = Zip.default_compression, encrypter = NullEncrypter.new)
|
4
6
|
super()
|
5
7
|
@output_stream = output_stream
|
@@ -13,16 +15,16 @@ module Zip
|
|
13
15
|
val = data.to_s
|
14
16
|
@crc = Zlib.crc32(val, @crc)
|
15
17
|
@size += val.bytesize
|
16
|
-
buffer = @zlib_deflater.deflate(data)
|
17
|
-
if buffer.empty?
|
18
|
-
|
19
|
-
|
20
|
-
@output_stream << @encrypter.encrypt(buffer)
|
21
|
-
end
|
18
|
+
buffer = @zlib_deflater.deflate(data, Zlib::SYNC_FLUSH)
|
19
|
+
return @output_stream if buffer.empty?
|
20
|
+
|
21
|
+
@output_stream << @encrypter.encrypt(buffer)
|
22
22
|
end
|
23
23
|
|
24
24
|
def finish
|
25
|
-
|
25
|
+
buffer = @zlib_deflater.finish
|
26
|
+
@output_stream << @encrypter.encrypt(buffer) unless buffer.empty?
|
27
|
+
@zlib_deflater.close
|
26
28
|
end
|
27
29
|
|
28
30
|
attr_reader :size, :crc
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zip
|
4
|
+
module Dirtyable # :nodoc:all
|
5
|
+
def initialize(dirty_on_create: true)
|
6
|
+
@dirty = dirty_on_create
|
7
|
+
end
|
8
|
+
|
9
|
+
def dirty?
|
10
|
+
@dirty
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods # :nodoc:
|
14
|
+
def mark_dirty(*symbols) # :nodoc:
|
15
|
+
# Move the original method and call it after we've set the dirty flag.
|
16
|
+
symbols.each do |symbol|
|
17
|
+
orig_name = "orig_#{symbol}"
|
18
|
+
alias_method orig_name, symbol
|
19
|
+
|
20
|
+
define_method(symbol) do |param|
|
21
|
+
@dirty = true
|
22
|
+
send(orig_name, param)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.extend(ClassMethods)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/zip/dos_time.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
1
5
|
module Zip
|
2
|
-
class DOSTime < Time
|
6
|
+
class DOSTime < Time # :nodoc:all
|
3
7
|
# MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
|
4
8
|
|
5
9
|
# Register CX, the Time:
|
@@ -25,8 +29,7 @@ module Zip
|
|
25
29
|
end
|
26
30
|
|
27
31
|
def dos_equals(other)
|
28
|
-
Zip
|
29
|
-
|
32
|
+
warn 'Zip::DOSTime#dos_equals is deprecated. Use `==` instead.'
|
30
33
|
self == other
|
31
34
|
end
|
32
35
|
|
@@ -52,6 +55,32 @@ module Zip
|
|
52
55
|
|
53
56
|
local(year, month, day, hour, minute, second)
|
54
57
|
end
|
58
|
+
|
59
|
+
if defined? JRUBY_VERSION && Gem::Version.new(JRUBY_VERSION) < '9.2.18.0'
|
60
|
+
module JRubyCMP # :nodoc:
|
61
|
+
def ==(other)
|
62
|
+
(self <=> other).zero?
|
63
|
+
end
|
64
|
+
|
65
|
+
def <(other)
|
66
|
+
(self <=> other).negative?
|
67
|
+
end
|
68
|
+
|
69
|
+
def <=(other)
|
70
|
+
(self <=> other) <= 0
|
71
|
+
end
|
72
|
+
|
73
|
+
def >(other)
|
74
|
+
(self <=> other).positive?
|
75
|
+
end
|
76
|
+
|
77
|
+
def >=(other)
|
78
|
+
(self <=> other) >= 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
include JRubyCMP
|
83
|
+
end
|
55
84
|
end
|
56
85
|
end
|
57
86
|
|