rubyzip 3.0.0.alpha → 3.0.0.rc2

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?
111
- gp_flags & 8 == 8
115
+ def incomplete? # :nodoc:
116
+ (gp_flags & 8 == 8) && (crc == 0 || size == 0 || compressed_size == 0)
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,26 +341,27 @@ 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
- @local_header_offset = io.tell
346
+ current_offset = io.tell
320
347
 
321
- static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
348
+ read_local_header_fields(io)
322
349
 
323
- unless static_sized_fields_buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
324
- raise Error, 'Premature end of file. Not enough data for zip entry local header'
325
- end
350
+ if @header_signature == SPLIT_FILE_SIGNATURE
351
+ raise SplitArchiveError if current_offset.zero?
326
352
 
327
- unpack_local_entry(static_sized_fields_buf)
353
+ # Rewind, skipping the data descriptor, then try to read the local header again.
354
+ current_offset += 16
355
+ io.seek(current_offset)
356
+ read_local_header_fields(io)
357
+ end
328
358
 
329
359
  unless @header_signature == LOCAL_ENTRY_SIGNATURE
330
- if @header_signature == SPLIT_FILE_SIGNATURE
331
- raise SplitArchiveError
332
- end
333
-
334
- raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
360
+ raise Error, "Zip local header magic not found at location '#{current_offset}'"
335
361
  end
336
362
 
363
+ @local_header_offset = current_offset
364
+
337
365
  set_time(@last_mod_date, @last_mod_time)
338
366
 
339
367
  @name = io.read(@name_length)
@@ -356,7 +384,7 @@ module Zip
356
384
  @local_header_size = calculate_local_header_size
357
385
  end
358
386
 
359
- def pack_local_entry
387
+ def pack_local_entry # :nodoc:
360
388
  zip64 = @extra['Zip64']
361
389
  [::Zip::LOCAL_ENTRY_SIGNATURE,
362
390
  @version_needed_to_extract, # version needed to extract
@@ -371,7 +399,7 @@ module Zip
371
399
  @extra ? @extra.local_size : 0].pack('VvvvvvVVVvv')
372
400
  end
373
401
 
374
- def write_local_entry(io, rewrite: false) #:nodoc:all
402
+ def write_local_entry(io, rewrite: false) # :nodoc:
375
403
  prep_local_zip64_extra
376
404
  verify_local_header_size! if rewrite
377
405
  @local_header_offset = io.tell
@@ -383,7 +411,7 @@ module Zip
383
411
  @local_header_size = io.tell - @local_header_offset
384
412
  end
385
413
 
386
- def unpack_c_dir_entry(buf)
414
+ def unpack_c_dir_entry(buf) # :nodoc:
387
415
  @header_signature,
388
416
  @version, # version of encoding software
389
417
  @fstype, # filesystem type
@@ -407,7 +435,7 @@ module Zip
407
435
  @comment = buf.unpack('VCCvvvvvVVVvvvvvVV')
408
436
  end
409
437
 
410
- def set_ftype_from_c_dir_entry
438
+ def set_ftype_from_c_dir_entry # :nodoc:
411
439
  @ftype = case @fstype
412
440
  when ::Zip::FSTYPE_UNIX
413
441
  @unix_perms = (@external_file_attributes >> 16) & 0o7777
@@ -437,25 +465,25 @@ module Zip
437
465
  end
438
466
  end
439
467
 
440
- def check_c_dir_entry_static_header_length(buf)
468
+ def check_c_dir_entry_static_header_length(buf) # :nodoc:
441
469
  return unless buf.nil? || buf.bytesize != ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
442
470
 
443
471
  raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
444
472
  end
445
473
 
446
- def check_c_dir_entry_signature
474
+ def check_c_dir_entry_signature # :nodoc:
447
475
  return if @header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
448
476
 
449
477
  raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
450
478
  end
451
479
 
452
- def check_c_dir_entry_comment_size
480
+ def check_c_dir_entry_comment_size # :nodoc:
453
481
  return if @comment && @comment.bytesize == @comment_length
454
482
 
455
483
  raise ::Zip::Error, 'Truncated cdir zip entry header'
456
484
  end
457
485
 
458
- def read_extra_field(buf, local: false)
486
+ def read_extra_field(buf, local: false) # :nodoc:
459
487
  if @extra.kind_of?(::Zip::ExtraField)
460
488
  @extra.merge(buf, local: local) if buf
461
489
  else
@@ -463,7 +491,7 @@ module Zip
463
491
  end
464
492
  end
465
493
 
466
- def read_c_dir_entry(io) #:nodoc:all
494
+ def read_c_dir_entry(io) # :nodoc:
467
495
  @dirty = false # No changes at this point.
468
496
  static_sized_fields_buf = io.read(::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH)
469
497
  check_c_dir_entry_static_header_length(static_sized_fields_buf)
@@ -503,7 +531,7 @@ module Zip
503
531
  end
504
532
 
505
533
  # rubocop:disable Style/GuardClause
506
- def set_unix_attributes_on_path(dest_path)
534
+ def set_unix_attributes_on_path(dest_path) # :nodoc:
507
535
  # Ignore setuid/setgid bits by default. Honour if @restore_ownership.
508
536
  unix_perms_mask = (@restore_ownership ? 0o7777 : 0o1777)
509
537
  if @restore_permissions && @unix_perms
@@ -529,7 +557,7 @@ module Zip
529
557
  ::FileUtils.touch(dest_path, mtime: time) if @restore_times
530
558
  end
531
559
 
532
- def pack_c_dir_entry
560
+ def pack_c_dir_entry # :nodoc:
533
561
  zip64 = @extra['Zip64']
534
562
  [
535
563
  @header_signature,
@@ -556,7 +584,7 @@ module Zip
556
584
  ].pack('VCCvvvvvVVVvvvvvVV')
557
585
  end
558
586
 
559
- def write_c_dir_entry(io) #:nodoc:all
587
+ def write_c_dir_entry(io) # :nodoc:
560
588
  prep_cdir_zip64_extra
561
589
 
562
590
  case @fstype
@@ -574,7 +602,7 @@ module Zip
574
602
  end
575
603
 
576
604
  unless ft.nil?
577
- @external_file_attributes = (ft << 12 | (@unix_perms & 0o7777)) << 16
605
+ @external_file_attributes = ((ft << 12) | (@unix_perms & 0o7777)) << 16
578
606
  end
579
607
  end
580
608
 
@@ -585,7 +613,7 @@ module Zip
585
613
  io << @comment
586
614
  end
587
615
 
588
- def ==(other)
616
+ def ==(other) # :nodoc:
589
617
  return false unless other.class == self.class
590
618
 
591
619
  # Compares contents of local entry and exposed fields
@@ -594,7 +622,7 @@ module Zip
594
622
  end
595
623
  end
596
624
 
597
- def <=>(other)
625
+ def <=>(other) # :nodoc:
598
626
  to_s <=> other.to_s
599
627
  end
600
628
 
@@ -639,7 +667,7 @@ module Zip
639
667
  if name_is_directory?
640
668
  raise ArgumentError,
641
669
  "entry name '#{newEntry}' indicates directory entry, but " \
642
- "'#{src_path}' is not a directory"
670
+ "'#{src_path}' is not a directory"
643
671
  end
644
672
  :file
645
673
  when 'directory'
@@ -649,7 +677,7 @@ module Zip
649
677
  if name_is_directory?
650
678
  raise ArgumentError,
651
679
  "entry name '#{newEntry}' indicates directory entry, but " \
652
- "'#{src_path}' is not a directory"
680
+ "'#{src_path}' is not a directory"
653
681
  end
654
682
  :symlink
655
683
  else
@@ -661,7 +689,7 @@ module Zip
661
689
  get_extra_attributes_from_path(@filepath)
662
690
  end
663
691
 
664
- def write_to_zip_output_stream(zip_output_stream) #:nodoc:all
692
+ def write_to_zip_output_stream(zip_output_stream) # :nodoc:
665
693
  if ftype == :directory
666
694
  zip_output_stream.put_next_entry(self)
667
695
  elsif @filepath
@@ -674,13 +702,13 @@ module Zip
674
702
  end
675
703
  end
676
704
 
677
- def parent_as_string
705
+ def parent_as_string # :nodoc:
678
706
  entry_name = name.chomp('/')
679
707
  slash_index = entry_name.rindex('/')
680
708
  slash_index ? entry_name.slice(0, slash_index + 1) : nil
681
709
  end
682
710
 
683
- def get_raw_input_stream(&block)
711
+ def get_raw_input_stream(&block) # :nodoc:
684
712
  if @zipfile.respond_to?(:seek) && @zipfile.respond_to?(:read)
685
713
  yield @zipfile
686
714
  else
@@ -688,12 +716,22 @@ module Zip
688
716
  end
689
717
  end
690
718
 
691
- def clean_up
719
+ def clean_up # :nodoc:
692
720
  @dirty = false # Any changes are written at this point.
693
721
  end
694
722
 
695
723
  private
696
724
 
725
+ def read_local_header_fields(io) # :nodoc:
726
+ static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
727
+
728
+ unless static_sized_fields_buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
729
+ raise Error, 'Premature end of file. Not enough data for zip entry local header'
730
+ end
731
+
732
+ unpack_local_entry(static_sized_fields_buf)
733
+ end
734
+
697
735
  def set_time(binary_dos_date, binary_dos_time)
698
736
  @time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
699
737
  rescue ArgumentError
@@ -749,7 +787,7 @@ module Zip
749
787
 
750
788
  # apply missing data from the zip64 extra information field, if present
751
789
  # (required when file sizes exceed 2**32, but can be used for all files)
752
- def parse_zip64_extra(for_local_header) #:nodoc:all
790
+ def parse_zip64_extra(for_local_header) # :nodoc:
753
791
  return unless zip64?
754
792
 
755
793
  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