rubyzip 3.0.0.alpha → 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.
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