rubyzip 3.0.0.alpha → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/zip/entry.rb CHANGED
@@ -9,16 +9,19 @@ module Zip
9
9
  class Entry
10
10
  include Dirtyable
11
11
 
12
+ # Constant used to specify that the entry is stored (i.e., not compressed).
12
13
  STORED = ::Zip::COMPRESSION_METHOD_STORE
14
+
15
+ # Constant used to specify that the entry is deflated (i.e., compressed).
13
16
  DEFLATED = ::Zip::COMPRESSION_METHOD_DEFLATE
14
17
 
15
18
  # Language encoding flag (EFS) bit
16
- EFS = 0b100000000000
19
+ EFS = 0b100000000000 # :nodoc:
17
20
 
18
21
  # Compression level flags (used as part of the gp flags).
19
- COMPRESSION_LEVEL_SUPERFAST_GPFLAG = 0b110
20
- COMPRESSION_LEVEL_FAST_GPFLAG = 0b100
21
- COMPRESSION_LEVEL_MAX_GPFLAG = 0b010
22
+ COMPRESSION_LEVEL_SUPERFAST_GPFLAG = 0b110 # :nodoc:
23
+ COMPRESSION_LEVEL_FAST_GPFLAG = 0b100 # :nodoc:
24
+ COMPRESSION_LEVEL_MAX_GPFLAG = 0b010 # :nodoc:
22
25
 
23
26
  attr_accessor :comment, :compressed_size, :follow_symlinks, :name,
24
27
  :restore_ownership, :restore_permissions, :restore_times,
@@ -35,7 +38,7 @@ module Zip
35
38
  :fstype=, :gp_flags=, :name=, :size=,
36
39
  :unix_gid=, :unix_perms=, :unix_uid=
37
40
 
38
- def set_default_vars_values
41
+ def set_default_vars_values # :nodoc:
39
42
  @local_header_offset = 0
40
43
  @local_header_size = nil # not known until local entry is created or read
41
44
  @internal_file_attributes = 1
@@ -63,11 +66,12 @@ module Zip
63
66
  @unix_perms = nil
64
67
  end
65
68
 
66
- def check_name(name)
69
+ def check_name(name) # :nodoc:
67
70
  raise EntryNameError, name if name.start_with?('/')
68
71
  raise EntryNameError if name.length > 65_535
69
72
  end
70
73
 
74
+ # Create a new Zip::Entry.
71
75
  def initialize(
72
76
  zipfile = '', name = '',
73
77
  comment: '', size: nil, compressed_size: 0, crc: 0,
@@ -103,18 +107,23 @@ module Zip
103
107
  set_compression_level_flags
104
108
  end
105
109
 
110
+ # Is this entry encrypted?
106
111
  def encrypted?
107
112
  gp_flags & 1 == 1
108
113
  end
109
114
 
110
- def incomplete?
115
+ def incomplete? # :nodoc:
111
116
  gp_flags & 8 == 8
112
117
  end
113
118
 
119
+ # The uncompressed size of the entry.
114
120
  def size
115
121
  @size || 0
116
122
  end
117
123
 
124
+ # Get a timestamp component of this entry.
125
+ #
126
+ # Returns modification time by default.
118
127
  def time(component: :mtime)
119
128
  time =
120
129
  if @extra['UniversalTime']
@@ -130,14 +139,19 @@ module Zip
130
139
 
131
140
  alias mtime time
132
141
 
142
+ # Get the last access time of this entry, if available.
133
143
  def atime
134
144
  time(component: :atime)
135
145
  end
136
146
 
147
+ # Get the creation time of this entry, if available.
137
148
  def ctime
138
149
  time(component: :ctime)
139
150
  end
140
151
 
152
+ # Set a timestamp component of this entry.
153
+ #
154
+ # Sets modification time by default.
141
155
  def time=(value, component: :mtime)
142
156
  @dirty = true
143
157
  unless @extra.member?('UniversalTime') || @extra.member?('NTFS')
@@ -152,30 +166,43 @@ module Zip
152
166
 
153
167
  alias mtime= time=
154
168
 
169
+ # Set the last access time of this entry.
155
170
  def atime=(value)
156
171
  send(:time=, value, component: :atime)
157
172
  end
158
173
 
174
+ # Set the creation time of this entry.
159
175
  def ctime=(value)
160
176
  send(:time=, value, component: :ctime)
161
177
  end
162
178
 
179
+ # Does this entry return time fields with accurate timezone information?
180
+ def absolute_time?
181
+ @extra.member?('UniversalTime') || @extra.member?('NTFS')
182
+ end
183
+
184
+ # Return the compression method for this entry.
185
+ #
186
+ # Returns STORED if the entry is a directory or if the compression
187
+ # level is 0.
163
188
  def compression_method
164
189
  return STORED if ftype == :directory || @compression_level == 0
165
190
 
166
191
  @compression_method
167
192
  end
168
193
 
194
+ # Set the compression method for this entry.
169
195
  def compression_method=(method)
170
196
  @dirty = true
171
197
  @compression_method = (ftype == :directory ? STORED : method)
172
198
  end
173
199
 
200
+ # Does this entry use the ZIP64 extensions?
174
201
  def zip64?
175
202
  !@extra['Zip64'].nil?
176
203
  end
177
204
 
178
- def file_type_is?(type)
205
+ def file_type_is?(type) # :nodoc:
179
206
  ftype == type
180
207
  end
181
208
 
@@ -185,19 +212,19 @@ module Zip
185
212
 
186
213
  # Dynamic checkers
187
214
  %w[directory file symlink].each do |k|
188
- define_method "#{k}?" do
215
+ define_method :"#{k}?" do
189
216
  file_type_is?(k.to_sym)
190
217
  end
191
218
  end
192
219
 
193
- def name_is_directory? #:nodoc:all
220
+ def name_is_directory? # :nodoc:
194
221
  @name.end_with?('/')
195
222
  end
196
223
 
197
224
  # Is the name a relative path, free of `..` patterns that could lead to
198
225
  # path traversal attacks? This does NOT handle symlinks; if the path
199
226
  # contains symlinks, this check is NOT enough to guarantee safety.
200
- def name_safe?
227
+ def name_safe? # :nodoc:
201
228
  cleanpath = Pathname.new(@name).cleanpath
202
229
  return false unless cleanpath.relative?
203
230
 
@@ -207,29 +234,29 @@ module Zip
207
234
  ::File.absolute_path(cleanpath.to_s, root).match?(/([A-Z]:)?#{naive}/i)
208
235
  end
209
236
 
210
- def local_entry_offset #:nodoc:all
237
+ def local_entry_offset # :nodoc:
211
238
  local_header_offset + @local_header_size
212
239
  end
213
240
 
214
- def name_size
241
+ def name_size # :nodoc:
215
242
  @name ? @name.bytesize : 0
216
243
  end
217
244
 
218
- def extra_size
245
+ def extra_size # :nodoc:
219
246
  @extra ? @extra.local_size : 0
220
247
  end
221
248
 
222
- def comment_size
249
+ def comment_size # :nodoc:
223
250
  @comment ? @comment.bytesize : 0
224
251
  end
225
252
 
226
- def calculate_local_header_size #:nodoc:all
253
+ def calculate_local_header_size # :nodoc:
227
254
  LOCAL_ENTRY_STATIC_HEADER_LENGTH + name_size + extra_size
228
255
  end
229
256
 
230
257
  # check before rewriting an entry (after file sizes are known)
231
258
  # that we didn't change the header size (and thus clobber file data or something)
232
- def verify_local_header_size!
259
+ def verify_local_header_size! # :nodoc:
233
260
  return if @local_header_size.nil?
234
261
 
235
262
  new_size = calculate_local_header_size
@@ -239,12 +266,12 @@ module Zip
239
266
  "Local header size changed (#{@local_header_size} -> #{new_size})"
240
267
  end
241
268
 
242
- def cdir_header_size #:nodoc:all
269
+ def cdir_header_size # :nodoc:
243
270
  CDIR_ENTRY_STATIC_HEADER_LENGTH + name_size +
244
271
  (@extra ? @extra.c_dir_size : 0) + comment_size
245
272
  end
246
273
 
247
- def next_header_offset #:nodoc:all
274
+ def next_header_offset # :nodoc:
248
275
  local_entry_offset + compressed_size
249
276
  end
250
277
 
@@ -266,16 +293,16 @@ module Zip
266
293
 
267
294
  raise "unknown file type #{inspect}" unless directory? || file? || symlink?
268
295
 
269
- __send__("create_#{ftype}", extract_path, &block)
296
+ __send__(:"create_#{ftype}", extract_path, &block)
270
297
  self
271
298
  end
272
299
 
273
- def to_s
300
+ def to_s # :nodoc:
274
301
  @name
275
302
  end
276
303
 
277
304
  class << self
278
- def read_c_dir_entry(io) #:nodoc:all
305
+ def read_c_dir_entry(io) # :nodoc:
279
306
  path = if io.respond_to?(:path)
280
307
  io.path
281
308
  else
@@ -288,7 +315,7 @@ module Zip
288
315
  nil
289
316
  end
290
317
 
291
- def read_local_entry(io)
318
+ def read_local_entry(io) # :nodoc:
292
319
  entry = new(io)
293
320
  entry.read_local_entry(io)
294
321
  entry
@@ -299,7 +326,7 @@ module Zip
299
326
  end
300
327
  end
301
328
 
302
- def unpack_local_entry(buf)
329
+ def unpack_local_entry(buf) # :nodoc:
303
330
  @header_signature,
304
331
  @version,
305
332
  @fstype,
@@ -314,7 +341,7 @@ module Zip
314
341
  @extra_length = buf.unpack('VCCvvvvVVVvv')
315
342
  end
316
343
 
317
- def read_local_entry(io) #:nodoc:all
344
+ def read_local_entry(io) # :nodoc:
318
345
  @dirty = false # No changes at this point.
319
346
  @local_header_offset = io.tell
320
347
 
@@ -356,7 +383,7 @@ module Zip
356
383
  @local_header_size = calculate_local_header_size
357
384
  end
358
385
 
359
- def pack_local_entry
386
+ def pack_local_entry # :nodoc:
360
387
  zip64 = @extra['Zip64']
361
388
  [::Zip::LOCAL_ENTRY_SIGNATURE,
362
389
  @version_needed_to_extract, # version needed to extract
@@ -371,7 +398,7 @@ module Zip
371
398
  @extra ? @extra.local_size : 0].pack('VvvvvvVVVvv')
372
399
  end
373
400
 
374
- def write_local_entry(io, rewrite: false) #:nodoc:all
401
+ def write_local_entry(io, rewrite: false) # :nodoc:
375
402
  prep_local_zip64_extra
376
403
  verify_local_header_size! if rewrite
377
404
  @local_header_offset = io.tell
@@ -383,7 +410,7 @@ module Zip
383
410
  @local_header_size = io.tell - @local_header_offset
384
411
  end
385
412
 
386
- def unpack_c_dir_entry(buf)
413
+ def unpack_c_dir_entry(buf) # :nodoc:
387
414
  @header_signature,
388
415
  @version, # version of encoding software
389
416
  @fstype, # filesystem type
@@ -407,7 +434,7 @@ module Zip
407
434
  @comment = buf.unpack('VCCvvvvvVVVvvvvvVV')
408
435
  end
409
436
 
410
- def set_ftype_from_c_dir_entry
437
+ def set_ftype_from_c_dir_entry # :nodoc:
411
438
  @ftype = case @fstype
412
439
  when ::Zip::FSTYPE_UNIX
413
440
  @unix_perms = (@external_file_attributes >> 16) & 0o7777
@@ -437,25 +464,25 @@ module Zip
437
464
  end
438
465
  end
439
466
 
440
- def check_c_dir_entry_static_header_length(buf)
467
+ def check_c_dir_entry_static_header_length(buf) # :nodoc:
441
468
  return unless buf.nil? || buf.bytesize != ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
442
469
 
443
470
  raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
444
471
  end
445
472
 
446
- def check_c_dir_entry_signature
473
+ def check_c_dir_entry_signature # :nodoc:
447
474
  return if @header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
448
475
 
449
476
  raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
450
477
  end
451
478
 
452
- def check_c_dir_entry_comment_size
479
+ def check_c_dir_entry_comment_size # :nodoc:
453
480
  return if @comment && @comment.bytesize == @comment_length
454
481
 
455
482
  raise ::Zip::Error, 'Truncated cdir zip entry header'
456
483
  end
457
484
 
458
- def read_extra_field(buf, local: false)
485
+ def read_extra_field(buf, local: false) # :nodoc:
459
486
  if @extra.kind_of?(::Zip::ExtraField)
460
487
  @extra.merge(buf, local: local) if buf
461
488
  else
@@ -463,7 +490,7 @@ module Zip
463
490
  end
464
491
  end
465
492
 
466
- def read_c_dir_entry(io) #:nodoc:all
493
+ def read_c_dir_entry(io) # :nodoc:
467
494
  @dirty = false # No changes at this point.
468
495
  static_sized_fields_buf = io.read(::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH)
469
496
  check_c_dir_entry_static_header_length(static_sized_fields_buf)
@@ -503,7 +530,7 @@ module Zip
503
530
  end
504
531
 
505
532
  # rubocop:disable Style/GuardClause
506
- def set_unix_attributes_on_path(dest_path)
533
+ def set_unix_attributes_on_path(dest_path) # :nodoc:
507
534
  # Ignore setuid/setgid bits by default. Honour if @restore_ownership.
508
535
  unix_perms_mask = (@restore_ownership ? 0o7777 : 0o1777)
509
536
  if @restore_permissions && @unix_perms
@@ -529,7 +556,7 @@ module Zip
529
556
  ::FileUtils.touch(dest_path, mtime: time) if @restore_times
530
557
  end
531
558
 
532
- def pack_c_dir_entry
559
+ def pack_c_dir_entry # :nodoc:
533
560
  zip64 = @extra['Zip64']
534
561
  [
535
562
  @header_signature,
@@ -556,7 +583,7 @@ module Zip
556
583
  ].pack('VCCvvvvvVVVvvvvvVV')
557
584
  end
558
585
 
559
- def write_c_dir_entry(io) #:nodoc:all
586
+ def write_c_dir_entry(io) # :nodoc:
560
587
  prep_cdir_zip64_extra
561
588
 
562
589
  case @fstype
@@ -574,7 +601,7 @@ module Zip
574
601
  end
575
602
 
576
603
  unless ft.nil?
577
- @external_file_attributes = (ft << 12 | (@unix_perms & 0o7777)) << 16
604
+ @external_file_attributes = ((ft << 12) | (@unix_perms & 0o7777)) << 16
578
605
  end
579
606
  end
580
607
 
@@ -585,7 +612,7 @@ module Zip
585
612
  io << @comment
586
613
  end
587
614
 
588
- def ==(other)
615
+ def ==(other) # :nodoc:
589
616
  return false unless other.class == self.class
590
617
 
591
618
  # Compares contents of local entry and exposed fields
@@ -594,7 +621,7 @@ module Zip
594
621
  end
595
622
  end
596
623
 
597
- def <=>(other)
624
+ def <=>(other) # :nodoc:
598
625
  to_s <=> other.to_s
599
626
  end
600
627
 
@@ -639,7 +666,7 @@ module Zip
639
666
  if name_is_directory?
640
667
  raise ArgumentError,
641
668
  "entry name '#{newEntry}' indicates directory entry, but " \
642
- "'#{src_path}' is not a directory"
669
+ "'#{src_path}' is not a directory"
643
670
  end
644
671
  :file
645
672
  when 'directory'
@@ -649,7 +676,7 @@ module Zip
649
676
  if name_is_directory?
650
677
  raise ArgumentError,
651
678
  "entry name '#{newEntry}' indicates directory entry, but " \
652
- "'#{src_path}' is not a directory"
679
+ "'#{src_path}' is not a directory"
653
680
  end
654
681
  :symlink
655
682
  else
@@ -661,7 +688,7 @@ module Zip
661
688
  get_extra_attributes_from_path(@filepath)
662
689
  end
663
690
 
664
- def write_to_zip_output_stream(zip_output_stream) #:nodoc:all
691
+ def write_to_zip_output_stream(zip_output_stream) # :nodoc:
665
692
  if ftype == :directory
666
693
  zip_output_stream.put_next_entry(self)
667
694
  elsif @filepath
@@ -674,13 +701,13 @@ module Zip
674
701
  end
675
702
  end
676
703
 
677
- def parent_as_string
704
+ def parent_as_string # :nodoc:
678
705
  entry_name = name.chomp('/')
679
706
  slash_index = entry_name.rindex('/')
680
707
  slash_index ? entry_name.slice(0, slash_index + 1) : nil
681
708
  end
682
709
 
683
- def get_raw_input_stream(&block)
710
+ def get_raw_input_stream(&block) # :nodoc:
684
711
  if @zipfile.respond_to?(:seek) && @zipfile.respond_to?(:read)
685
712
  yield @zipfile
686
713
  else
@@ -688,7 +715,7 @@ module Zip
688
715
  end
689
716
  end
690
717
 
691
- def clean_up
718
+ def clean_up # :nodoc:
692
719
  @dirty = false # Any changes are written at this point.
693
720
  end
694
721
 
@@ -749,7 +776,7 @@ module Zip
749
776
 
750
777
  # apply missing data from the zip64 extra information field, if present
751
778
  # (required when file sizes exceed 2**32, but can be used for all files)
752
- def parse_zip64_extra(for_local_header) #:nodoc:all
779
+ def parse_zip64_extra(for_local_header) # :nodoc:
753
780
  return unless zip64?
754
781
 
755
782
  if for_local_header
data/lib/zip/entry_set.rb CHANGED
@@ -61,12 +61,12 @@ module Zip
61
61
  end
62
62
 
63
63
  def glob(pattern, flags = ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH | ::File::FNM_EXTGLOB)
64
- entries.map do |entry|
64
+ entries.filter_map do |entry|
65
65
  next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
66
66
 
67
67
  yield(entry) if block_given?
68
68
  entry
69
- end.compact
69
+ end
70
70
  end
71
71
 
72
72
  protected
data/lib/zip/errors.rb CHANGED
@@ -7,13 +7,17 @@ module Zip
7
7
 
8
8
  # Error raised if an unsupported compression method is used.
9
9
  class CompressionMethodError < Error
10
+ # The compression method that has caused this error.
10
11
  attr_reader :compression_method
11
12
 
13
+ # Create a new CompressionMethodError with the specified incorrect
14
+ # compression method.
12
15
  def initialize(method)
13
16
  super()
14
17
  @compression_method = method
15
18
  end
16
19
 
20
+ # The message returned by this error.
17
21
  def message
18
22
  "Unsupported compression method: #{COMPRESSION_METHODS[@compression_method]}."
19
23
  end
@@ -21,13 +25,17 @@ module Zip
21
25
 
22
26
  # Error raised if there is a problem while decompressing an archive entry.
23
27
  class DecompressionError < Error
28
+ # The error from the underlying Zlib library that caused this error.
24
29
  attr_reader :zlib_error
25
30
 
31
+ # Create a new DecompressionError with the specified underlying Zlib
32
+ # error.
26
33
  def initialize(zlib_error)
27
34
  super()
28
35
  @zlib_error = zlib_error
29
36
  end
30
37
 
38
+ # The message returned by this error.
31
39
  def message
32
40
  "Zlib error ('#{@zlib_error.message}') while inflating."
33
41
  end
@@ -36,26 +44,30 @@ module Zip
36
44
  # Error raised when trying to extract an archive entry over an
37
45
  # existing file.
38
46
  class DestinationExistsError < Error
47
+ # Create a new DestinationExistsError with the clashing destination.
39
48
  def initialize(destination)
40
49
  super()
41
50
  @destination = destination
42
51
  end
43
52
 
53
+ # The message returned by this error.
44
54
  def message
45
55
  "Cannot create file or directory '#{@destination}'. " \
46
- 'A file already exists with that name.'
56
+ 'A file already exists with that name.'
47
57
  end
48
58
  end
49
59
 
50
60
  # Error raised when trying to add an entry to an archive where the
51
61
  # entry name already exists.
52
62
  class EntryExistsError < Error
63
+ # Create a new EntryExistsError with the specified source and name.
53
64
  def initialize(source, name)
54
65
  super()
55
66
  @source = source
56
67
  @name = name
57
68
  end
58
69
 
70
+ # The message returned by this error.
59
71
  def message
60
72
  "'#{@source}' failed. Entry #{@name} already exists."
61
73
  end
@@ -63,11 +75,13 @@ module Zip
63
75
 
64
76
  # Error raised when an entry name is invalid.
65
77
  class EntryNameError < Error
78
+ # Create a new EntryNameError with the specified name.
66
79
  def initialize(name = nil)
67
80
  super()
68
81
  @name = name
69
82
  end
70
83
 
84
+ # The message returned by this error.
71
85
  def message
72
86
  if @name.nil?
73
87
  'Illegal entry name. Names must have fewer than 65,536 characters.'
@@ -80,13 +94,16 @@ module Zip
80
94
  # Error raised if an entry is larger on extraction than it is advertised
81
95
  # to be.
82
96
  class EntrySizeError < Error
97
+ # The entry that has caused this error.
83
98
  attr_reader :entry
84
99
 
100
+ # Create a new EntrySizeError with the specified entry.
85
101
  def initialize(entry)
86
102
  super()
87
103
  @entry = entry
88
104
  end
89
105
 
106
+ # The message returned by this error.
90
107
  def message
91
108
  "Entry '#{@entry.name}' should be #{@entry.size}B, but is larger when inflated."
92
109
  end
@@ -95,6 +112,7 @@ module Zip
95
112
  # Error raised if a split archive is read. Rubyzip does not support reading
96
113
  # split archives.
97
114
  class SplitArchiveError < Error
115
+ # The message returned by this error.
98
116
  def message
99
117
  'Rubyzip cannot extract from split archives at this time.'
100
118
  end
@@ -102,17 +120,20 @@ module Zip
102
120
 
103
121
  # Error raised if there is not enough metadata for the entry to be streamed.
104
122
  class StreamingError < Error
123
+ # The entry that has caused this error.
105
124
  attr_reader :entry
106
125
 
126
+ # Create a new StreamingError with the specified entry.
107
127
  def initialize(entry)
108
128
  super()
109
129
  @entry = entry
110
130
  end
111
131
 
132
+ # The message returned by this error.
112
133
  def message
113
134
  "The local header of this entry ('#{@entry.name}') does not contain " \
114
- 'the correct metadata for `Zip::InputStream` to be able to ' \
115
- 'uncompress it. Please use `Zip::File` instead of `Zip::InputStream`.'
135
+ 'the correct metadata for `Zip::InputStream` to be able to ' \
136
+ 'uncompress it. Please use `Zip::File` instead of `Zip::InputStream`.'
116
137
  end
117
138
  end
118
139
  end
@@ -21,17 +21,17 @@ module Zip
21
21
  return false
22
22
  end
23
23
 
24
- [binstr[2, 2].unpack1('v'), binstr[4..-1]]
24
+ [binstr[2, 2].unpack1('v'), binstr[4..]]
25
25
  end
26
26
 
27
27
  def to_local_bin
28
28
  s = pack_for_local
29
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
29
+ (self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v')) << s
30
30
  end
31
31
 
32
32
  def to_c_dir_bin
33
33
  s = pack_for_c_dir
34
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
34
+ (self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v')) << s
35
35
  end
36
36
  end
37
37
  end
@@ -25,7 +25,7 @@ module Zip
25
25
  size, content = initial_parse(binstr)
26
26
  (size && content) || return
27
27
 
28
- content = content[4..-1]
28
+ content = content[4..]
29
29
  tags = parse_tags(content)
30
30
 
31
31
  tag1 = tags[1]
@@ -86,7 +86,7 @@ module Zip
86
86
  end
87
87
 
88
88
  def from_ntfs_time(ntfs_time)
89
- ::Zip::DOSTime.at(ntfs_time / WINDOWS_TICK - SEC_TO_UNIX_EPOCH)
89
+ ::Zip::DOSTime.at((ntfs_time / WINDOWS_TICK) - SEC_TO_UNIX_EPOCH)
90
90
  end
91
91
 
92
92
  def to_ntfs_time(time)
@@ -21,8 +21,8 @@ module Zip
21
21
  def extra_field_type_unknown(binstr, len, index, local)
22
22
  self['Unknown'] ||= Unknown.new
23
23
 
24
- if !len || len + 4 > binstr[index..-1].bytesize
25
- self['Unknown'].merge(binstr[index..-1], local: local)
24
+ if !len || len + 4 > binstr[index..].bytesize
25
+ self['Unknown'].merge(binstr[index..], local: local)
26
26
  return
27
27
  end
28
28