rubyzip 1.2.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +64 -23
- data/Rakefile +3 -0
- data/lib/zip.rb +6 -3
- data/lib/zip/central_directory.rb +9 -5
- data/lib/zip/constants.rb +52 -0
- data/lib/zip/crypto/decrypted_io.rb +40 -0
- data/lib/zip/crypto/traditional_encryption.rb +9 -9
- data/lib/zip/decompressor.rb +19 -1
- data/lib/zip/dos_time.rb +12 -7
- data/lib/zip/entry.rb +69 -37
- data/lib/zip/entry_set.rb +2 -0
- data/lib/zip/errors.rb +2 -0
- data/lib/zip/extra_field.rb +11 -9
- data/lib/zip/extra_field/generic.rb +10 -9
- data/lib/zip/extra_field/ntfs.rb +4 -0
- data/lib/zip/extra_field/old_unix.rb +3 -1
- data/lib/zip/extra_field/universal_time.rb +42 -12
- data/lib/zip/extra_field/unix.rb +3 -1
- data/lib/zip/extra_field/zip64.rb +4 -2
- data/lib/zip/file.rb +115 -70
- data/lib/zip/filesystem.rb +193 -177
- data/lib/zip/inflater.rb +24 -36
- data/lib/zip/input_stream.rb +33 -26
- data/lib/zip/ioextras.rb +1 -1
- data/lib/zip/ioextras/abstract_input_stream.rb +19 -8
- data/lib/zip/ioextras/abstract_output_stream.rb +1 -1
- data/lib/zip/null_decompressor.rb +1 -9
- data/lib/zip/output_stream.rb +14 -5
- data/lib/zip/pass_thru_compressor.rb +2 -2
- data/lib/zip/pass_thru_decompressor.rb +13 -22
- data/lib/zip/streamable_directory.rb +3 -3
- data/lib/zip/streamable_stream.rb +6 -10
- data/lib/zip/version.rb +1 -1
- data/samples/example.rb +2 -2
- data/samples/example_filesystem.rb +1 -1
- data/samples/gtk_ruby_zip.rb +19 -19
- data/samples/qtzip.rb +6 -6
- data/samples/write_simple.rb +2 -4
- data/samples/zipfind.rb +23 -22
- metadata +32 -167
- 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.zip +0 -0
- data/test/data/globTest/foo.txt +0 -0
- data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
- data/test/data/globTest/food.txt +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/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 -83
- data/test/file_permissions_test.rb +0 -65
- data/test/file_split_test.rb +0 -57
- data/test/file_test.rb +0 -601
- 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 -134
- 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/decompressor.rb
CHANGED
@@ -1,9 +1,27 @@
|
|
1
1
|
module Zip
|
2
2
|
class Decompressor #:nodoc:all
|
3
3
|
CHUNK_SIZE = 32_768
|
4
|
-
|
4
|
+
|
5
|
+
def self.decompressor_classes
|
6
|
+
@decompressor_classes ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.register(compression_method, decompressor_class)
|
10
|
+
decompressor_classes[compression_method] = decompressor_class
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find_by_compression_method(compression_method)
|
14
|
+
decompressor_classes[compression_method]
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :input_stream
|
18
|
+
attr_reader :decompressed_size
|
19
|
+
|
20
|
+
def initialize(input_stream, decompressed_size = nil)
|
5
21
|
super()
|
22
|
+
|
6
23
|
@input_stream = input_stream
|
24
|
+
@decompressed_size = decompressed_size
|
7
25
|
end
|
8
26
|
end
|
9
27
|
end
|
data/lib/zip/dos_time.rb
CHANGED
@@ -29,13 +29,18 @@ module Zip
|
|
29
29
|
to_i / 2 == other.to_i / 2
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
# Create a DOSTime instance from a vanilla Time instance.
|
33
|
+
def self.from_time(time)
|
34
|
+
local(time.year, time.month, time.day, time.hour, time.min, time.sec)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.parse_binary_dos_format(bin_dos_date, bin_dos_time)
|
38
|
+
second = 2 * (0b11111 & bin_dos_time)
|
39
|
+
minute = (0b11111100000 & bin_dos_time) >> 5
|
40
|
+
hour = (0b1111100000000000 & bin_dos_time) >> 11
|
41
|
+
day = (0b11111 & bin_dos_date)
|
42
|
+
month = (0b111100000 & bin_dos_date) >> 5
|
43
|
+
year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
|
39
44
|
begin
|
40
45
|
local(year, month, day, hour, minute, second)
|
41
46
|
end
|
data/lib/zip/entry.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'pathname'
|
1
2
|
module Zip
|
2
3
|
class Entry
|
3
4
|
STORED = 0
|
@@ -33,7 +34,7 @@ module Zip
|
|
33
34
|
end
|
34
35
|
@follow_symlinks = false
|
35
36
|
|
36
|
-
@restore_times =
|
37
|
+
@restore_times = false
|
37
38
|
@restore_permissions = false
|
38
39
|
@restore_ownership = false
|
39
40
|
# BUG: need an extra field to support uid/gid's
|
@@ -47,6 +48,7 @@ module Zip
|
|
47
48
|
|
48
49
|
def check_name(name)
|
49
50
|
return unless name.start_with?('/')
|
51
|
+
|
50
52
|
raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
|
51
53
|
end
|
52
54
|
|
@@ -68,7 +70,15 @@ module Zip
|
|
68
70
|
@time = args[8] || ::Zip::DOSTime.now
|
69
71
|
|
70
72
|
@ftype = name_is_directory? ? :directory : :file
|
71
|
-
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.
|
73
|
+
@extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.kind_of?(::Zip::ExtraField)
|
74
|
+
end
|
75
|
+
|
76
|
+
def encrypted?
|
77
|
+
gp_flags & 1 == 1
|
78
|
+
end
|
79
|
+
|
80
|
+
def incomplete?
|
81
|
+
gp_flags & 8 == 8
|
72
82
|
end
|
73
83
|
|
74
84
|
def time
|
@@ -90,11 +100,12 @@ module Zip
|
|
90
100
|
@extra.create('UniversalTime')
|
91
101
|
end
|
92
102
|
(@extra['UniversalTime'] || @extra['NTFS']).mtime = value
|
93
|
-
@time
|
103
|
+
@time = value
|
94
104
|
end
|
95
105
|
|
96
106
|
def file_type_is?(type)
|
97
107
|
raise InternalError, "current filetype is unknown: #{inspect}" unless @ftype
|
108
|
+
|
98
109
|
@ftype == type
|
99
110
|
end
|
100
111
|
|
@@ -115,9 +126,10 @@ module Zip
|
|
115
126
|
def name_safe?
|
116
127
|
cleanpath = Pathname.new(@name).cleanpath
|
117
128
|
return false unless cleanpath.relative?
|
129
|
+
|
118
130
|
root = ::File::SEPARATOR
|
119
131
|
naive_expanded_path = ::File.join(root, cleanpath.to_s)
|
120
|
-
|
132
|
+
::File.absolute_path(cleanpath.to_s, root) == naive_expanded_path
|
121
133
|
end
|
122
134
|
|
123
135
|
def local_entry_offset #:nodoc:all
|
@@ -144,6 +156,7 @@ module Zip
|
|
144
156
|
# that we didn't change the header size (and thus clobber file data or something)
|
145
157
|
def verify_local_header_size!
|
146
158
|
return if @local_header_size.nil?
|
159
|
+
|
147
160
|
new_size = calculate_local_header_size
|
148
161
|
raise Error, "local header size changed (#{@local_header_size} -> #{new_size})" if @local_header_size != new_size
|
149
162
|
end
|
@@ -162,19 +175,16 @@ module Zip
|
|
162
175
|
# is passed.
|
163
176
|
def extract(dest_path = nil, &block)
|
164
177
|
if dest_path.nil? && !name_safe?
|
165
|
-
|
178
|
+
warn "WARNING: skipped '#{@name}' as unsafe."
|
166
179
|
return self
|
167
180
|
end
|
168
181
|
|
169
182
|
dest_path ||= @name
|
170
183
|
block ||= proc { ::Zip.on_exists_proc }
|
171
184
|
|
172
|
-
|
173
|
-
__send__("create_#{@ftype}", dest_path, &block)
|
174
|
-
else
|
175
|
-
raise "unknown file type #{inspect}"
|
176
|
-
end
|
185
|
+
raise "unknown file type #{inspect}" unless directory? || file? || symlink?
|
177
186
|
|
187
|
+
__send__("create_#{@ftype}", dest_path, &block)
|
178
188
|
self
|
179
189
|
end
|
180
190
|
|
@@ -184,15 +194,15 @@ module Zip
|
|
184
194
|
|
185
195
|
class << self
|
186
196
|
def read_zip_short(io) # :nodoc:
|
187
|
-
io.read(2).
|
197
|
+
io.read(2).unpack1('v')
|
188
198
|
end
|
189
199
|
|
190
200
|
def read_zip_long(io) # :nodoc:
|
191
|
-
io.read(4).
|
201
|
+
io.read(4).unpack1('V')
|
192
202
|
end
|
193
203
|
|
194
204
|
def read_zip_64_long(io) # :nodoc:
|
195
|
-
io.read(8).
|
205
|
+
io.read(8).unpack1('Q<')
|
196
206
|
end
|
197
207
|
|
198
208
|
def read_c_dir_entry(io) #:nodoc:all
|
@@ -217,8 +227,6 @@ module Zip
|
|
217
227
|
end
|
218
228
|
end
|
219
229
|
|
220
|
-
public
|
221
|
-
|
222
230
|
def unpack_local_entry(buf)
|
223
231
|
@header_signature,
|
224
232
|
@version,
|
@@ -248,6 +256,7 @@ module Zip
|
|
248
256
|
unless @header_signature == ::Zip::LOCAL_ENTRY_SIGNATURE
|
249
257
|
raise ::Zip::Error, "Zip local header magic not found at location '#{local_header_offset}'"
|
250
258
|
end
|
259
|
+
|
251
260
|
set_time(@last_mod_date, @last_mod_time)
|
252
261
|
|
253
262
|
@name = io.read(@name_length)
|
@@ -260,13 +269,14 @@ module Zip
|
|
260
269
|
|
261
270
|
if extra && extra.bytesize != @extra_length
|
262
271
|
raise ::Zip::Error, 'Truncated local zip entry header'
|
272
|
+
end
|
273
|
+
|
274
|
+
if @extra.kind_of?(::Zip::ExtraField)
|
275
|
+
@extra.merge(extra) if extra
|
263
276
|
else
|
264
|
-
|
265
|
-
@extra.merge(extra) if extra
|
266
|
-
else
|
267
|
-
@extra = ::Zip::ExtraField.new(extra)
|
268
|
-
end
|
277
|
+
@extra = ::Zip::ExtraField.new(extra)
|
269
278
|
end
|
279
|
+
|
270
280
|
parse_zip64_extra(true)
|
271
281
|
@local_header_size = calculate_local_header_size
|
272
282
|
end
|
@@ -275,10 +285,10 @@ module Zip
|
|
275
285
|
zip64 = @extra['Zip64']
|
276
286
|
[::Zip::LOCAL_ENTRY_SIGNATURE,
|
277
287
|
@version_needed_to_extract, # version needed to extract
|
278
|
-
@gp_flags, # @gp_flags
|
288
|
+
@gp_flags, # @gp_flags
|
279
289
|
@compression_method,
|
280
|
-
@time.to_binary_dos_time, # @last_mod_time
|
281
|
-
@time.to_binary_dos_date, # @last_mod_date
|
290
|
+
@time.to_binary_dos_time, # @last_mod_time
|
291
|
+
@time.to_binary_dos_date, # @last_mod_date
|
282
292
|
@crc,
|
283
293
|
zip64 && zip64.compressed_size ? 0xFFFFFFFF : @compressed_size,
|
284
294
|
zip64 && zip64.original_size ? 0xFFFFFFFF : @size,
|
@@ -353,21 +363,24 @@ module Zip
|
|
353
363
|
|
354
364
|
def check_c_dir_entry_static_header_length(buf)
|
355
365
|
return if buf.bytesize == ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
|
366
|
+
|
356
367
|
raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
|
357
368
|
end
|
358
369
|
|
359
370
|
def check_c_dir_entry_signature
|
360
371
|
return if header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
|
372
|
+
|
361
373
|
raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
|
362
374
|
end
|
363
375
|
|
364
376
|
def check_c_dir_entry_comment_size
|
365
377
|
return if @comment && @comment.bytesize == @comment_length
|
378
|
+
|
366
379
|
raise ::Zip::Error, 'Truncated cdir zip entry header'
|
367
380
|
end
|
368
381
|
|
369
382
|
def read_c_dir_extra_field(io)
|
370
|
-
if @extra.
|
383
|
+
if @extra.kind_of?(::Zip::ExtraField)
|
371
384
|
@extra.merge(io.read(@extra_length))
|
372
385
|
else
|
373
386
|
@extra = ::Zip::ExtraField.new(io.read(@extra_length))
|
@@ -401,20 +414,25 @@ module Zip
|
|
401
414
|
|
402
415
|
def get_extra_attributes_from_path(path) # :nodoc:
|
403
416
|
return if Zip::RUNNING_ON_WINDOWS
|
417
|
+
|
404
418
|
stat = file_stat(path)
|
405
419
|
@unix_uid = stat.uid
|
406
420
|
@unix_gid = stat.gid
|
407
421
|
@unix_perms = stat.mode & 0o7777
|
422
|
+
@time = ::Zip::DOSTime.from_time(stat.mtime)
|
408
423
|
end
|
409
424
|
|
410
|
-
def
|
411
|
-
# BUG: does not update timestamps into account
|
425
|
+
def set_unix_attributes_on_path(dest_path)
|
412
426
|
# ignore setuid/setgid bits by default. honor if @restore_ownership
|
413
427
|
unix_perms_mask = 0o1777
|
414
428
|
unix_perms_mask = 0o7777 if @restore_ownership
|
415
429
|
::FileUtils.chmod(@unix_perms & unix_perms_mask, dest_path) if @restore_permissions && @unix_perms
|
416
430
|
::FileUtils.chown(@unix_uid, @unix_gid, dest_path) if @restore_ownership && @unix_uid && @unix_gid && ::Process.egid == 0
|
417
|
-
|
431
|
+
|
432
|
+
# Restore the timestamp on a file. This will either have come from the
|
433
|
+
# original source file that was copied into the archive, or from the
|
434
|
+
# creation date of the archive if there was no original source file.
|
435
|
+
::FileUtils.touch(dest_path, mtime: time) if @restore_times
|
418
436
|
end
|
419
437
|
|
420
438
|
def set_extra_attributes_on_path(dest_path) # :nodoc:
|
@@ -422,7 +440,7 @@ module Zip
|
|
422
440
|
|
423
441
|
case @fstype
|
424
442
|
when ::Zip::FSTYPE_UNIX
|
425
|
-
|
443
|
+
set_unix_attributes_on_path(dest_path)
|
426
444
|
end
|
427
445
|
end
|
428
446
|
|
@@ -432,11 +450,11 @@ module Zip
|
|
432
450
|
@header_signature,
|
433
451
|
@version, # version of encoding software
|
434
452
|
@fstype, # filesystem type
|
435
|
-
@version_needed_to_extract, # @versionNeededToExtract
|
436
|
-
@gp_flags, # @gp_flags
|
453
|
+
@version_needed_to_extract, # @versionNeededToExtract
|
454
|
+
@gp_flags, # @gp_flags
|
437
455
|
@compression_method,
|
438
|
-
@time.to_binary_dos_time, # @last_mod_time
|
439
|
-
@time.to_binary_dos_date, # @last_mod_date
|
456
|
+
@time.to_binary_dos_time, # @last_mod_time
|
457
|
+
@time.to_binary_dos_date, # @last_mod_date
|
440
458
|
@crc,
|
441
459
|
zip64 && zip64.compressed_size ? 0xFFFFFFFF : @compressed_size,
|
442
460
|
zip64 && zip64.original_size ? 0xFFFFFFFF : @size,
|
@@ -483,6 +501,7 @@ module Zip
|
|
483
501
|
|
484
502
|
def ==(other)
|
485
503
|
return false unless other.class == self.class
|
504
|
+
|
486
505
|
# Compares contents of local entry and exposed fields
|
487
506
|
keys_equal = %w[compression_method crc compressed_size size name extra filepath].all? do |k|
|
488
507
|
other.__send__(k.to_sym) == __send__(k.to_sym)
|
@@ -590,7 +609,7 @@ module Zip
|
|
590
609
|
def set_time(binary_dos_date, binary_dos_time)
|
591
610
|
@time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
|
592
611
|
rescue ArgumentError
|
593
|
-
warn '
|
612
|
+
warn 'WARNING: invalid date/time in zip entry.' if ::Zip.warn_invalid_date
|
594
613
|
end
|
595
614
|
|
596
615
|
def create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
|
@@ -600,18 +619,29 @@ module Zip
|
|
600
619
|
end
|
601
620
|
::File.open(dest_path, 'wb') do |os|
|
602
621
|
get_input_stream do |is|
|
603
|
-
|
604
|
-
|
605
|
-
buf = ''
|
622
|
+
bytes_written = 0
|
623
|
+
warned = false
|
624
|
+
buf = +''
|
606
625
|
while (buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf))
|
607
626
|
os << buf
|
627
|
+
bytes_written += buf.bytesize
|
628
|
+
next unless bytes_written > size && !warned
|
629
|
+
|
630
|
+
message = "entry '#{name}' should be #{size}B, but is larger when inflated."
|
631
|
+
raise ::Zip::EntrySizeError, message if ::Zip.validate_entry_sizes
|
632
|
+
|
633
|
+
warn "WARNING: #{message}"
|
634
|
+
warned = true
|
608
635
|
end
|
609
636
|
end
|
610
637
|
end
|
638
|
+
|
639
|
+
set_extra_attributes_on_path(dest_path)
|
611
640
|
end
|
612
641
|
|
613
642
|
def create_directory(dest_path)
|
614
643
|
return if ::File.directory?(dest_path)
|
644
|
+
|
615
645
|
if ::File.exist?(dest_path)
|
616
646
|
if block_given? && yield(self, dest_path)
|
617
647
|
::FileUtils.rm_f dest_path
|
@@ -629,13 +659,14 @@ module Zip
|
|
629
659
|
def create_symlink(dest_path)
|
630
660
|
# TODO: Symlinks pose security challenges. Symlink support temporarily
|
631
661
|
# removed in view of https://github.com/rubyzip/rubyzip/issues/369 .
|
632
|
-
|
662
|
+
warn "WARNING: skipped symlink '#{dest_path}'."
|
633
663
|
end
|
634
664
|
|
635
665
|
# apply missing data from the zip64 extra information field, if present
|
636
666
|
# (required when file sizes exceed 2**32, but can be used for all files)
|
637
667
|
def parse_zip64_extra(for_local_header) #:nodoc:all
|
638
668
|
return if @extra['Zip64'].nil?
|
669
|
+
|
639
670
|
if for_local_header
|
640
671
|
@size, @compressed_size = @extra['Zip64'].parse(@size, @compressed_size)
|
641
672
|
else
|
@@ -650,6 +681,7 @@ module Zip
|
|
650
681
|
# create a zip64 extra information field if we need one
|
651
682
|
def prep_zip64_extra(for_local_header) #:nodoc:all
|
652
683
|
return unless ::Zip.write_zip64_support
|
684
|
+
|
653
685
|
need_zip64 = @size >= 0xFFFFFFFF || @compressed_size >= 0xFFFFFFFF
|
654
686
|
need_zip64 ||= @local_header_offset >= 0xFFFFFFFF unless for_local_header
|
655
687
|
if need_zip64
|
data/lib/zip/entry_set.rb
CHANGED
@@ -50,6 +50,7 @@ module Zip
|
|
50
50
|
|
51
51
|
def ==(other)
|
52
52
|
return false unless other.kind_of?(EntrySet)
|
53
|
+
|
53
54
|
@entry_set.values == other.entry_set.values
|
54
55
|
end
|
55
56
|
|
@@ -60,6 +61,7 @@ module Zip
|
|
60
61
|
def glob(pattern, flags = ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH | ::File::FNM_EXTGLOB)
|
61
62
|
entries.map do |entry|
|
62
63
|
next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
|
64
|
+
|
63
65
|
yield(entry) if block_given?
|
64
66
|
entry
|
65
67
|
end.compact
|
data/lib/zip/errors.rb
CHANGED
@@ -4,8 +4,10 @@ module Zip
|
|
4
4
|
class DestinationFileExistsError < Error; end
|
5
5
|
class CompressionMethodError < Error; end
|
6
6
|
class EntryNameError < Error; end
|
7
|
+
class EntrySizeError < Error; end
|
7
8
|
class InternalError < Error; end
|
8
9
|
class GPFBit3Error < Error; end
|
10
|
+
class DecompressionError < Error; end
|
9
11
|
|
10
12
|
# Backwards compatibility with v1 (delete in v2)
|
11
13
|
ZipError = Error
|
data/lib/zip/extra_field.rb
CHANGED
@@ -6,27 +6,27 @@ module Zip
|
|
6
6
|
merge(binstr) if binstr
|
7
7
|
end
|
8
8
|
|
9
|
-
def extra_field_type_exist(binstr, id, len,
|
9
|
+
def extra_field_type_exist(binstr, id, len, index)
|
10
10
|
field_name = ID_MAP[id].name
|
11
11
|
if member?(field_name)
|
12
|
-
self[field_name].merge(binstr[
|
12
|
+
self[field_name].merge(binstr[index, len + 4])
|
13
13
|
else
|
14
|
-
field_obj = ID_MAP[id].new(binstr[
|
14
|
+
field_obj = ID_MAP[id].new(binstr[index, len + 4])
|
15
15
|
self[field_name] = field_obj
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def extra_field_type_unknown(binstr, len,
|
19
|
+
def extra_field_type_unknown(binstr, len, index)
|
20
20
|
create_unknown_item unless self['Unknown']
|
21
|
-
if !len || len + 4 > binstr[
|
22
|
-
self['Unknown'] << binstr[
|
21
|
+
if !len || len + 4 > binstr[index..-1].bytesize
|
22
|
+
self['Unknown'] << binstr[index..-1]
|
23
23
|
return
|
24
24
|
end
|
25
|
-
self['Unknown'] << binstr[
|
25
|
+
self['Unknown'] << binstr[index, len + 4]
|
26
26
|
end
|
27
27
|
|
28
28
|
def create_unknown_item
|
29
|
-
s = ''
|
29
|
+
s = +''
|
30
30
|
class << s
|
31
31
|
alias_method :to_c_dir_bin, :to_s
|
32
32
|
alias_method :to_local_bin, :to_s
|
@@ -36,10 +36,11 @@ module Zip
|
|
36
36
|
|
37
37
|
def merge(binstr)
|
38
38
|
return if binstr.empty?
|
39
|
+
|
39
40
|
i = 0
|
40
41
|
while i < binstr.bytesize
|
41
42
|
id = binstr[i, 2]
|
42
|
-
len = binstr[i + 2, 2].to_s.
|
43
|
+
len = binstr[i + 2, 2].to_s.unpack1('v')
|
43
44
|
if id && ID_MAP.member?(id)
|
44
45
|
extra_field_type_exist(binstr, id, len, i)
|
45
46
|
elsif id
|
@@ -54,6 +55,7 @@ module Zip
|
|
54
55
|
unless (field_class = ID_MAP.values.find { |k| k.name == name })
|
55
56
|
raise Error, "Unknown extra field '#{name}'"
|
56
57
|
end
|
58
|
+
|
57
59
|
self[name] = field_class.new
|
58
60
|
end
|
59
61
|
|