rubyzip 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubyzip might be problematic. Click here for more details.

Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -17
  3. data/lib/zip.rb +9 -1
  4. data/lib/zip/central_directory.rb +3 -3
  5. data/lib/zip/compressor.rb +1 -2
  6. data/lib/zip/constants.rb +3 -3
  7. data/lib/zip/crypto/null_encryption.rb +2 -4
  8. data/lib/zip/decompressor.rb +1 -1
  9. data/lib/zip/dos_time.rb +1 -1
  10. data/lib/zip/entry.rb +46 -49
  11. data/lib/zip/entry_set.rb +3 -3
  12. data/lib/zip/extra_field.rb +1 -1
  13. data/lib/zip/extra_field/generic.rb +1 -1
  14. data/lib/zip/extra_field/zip64_placeholder.rb +1 -2
  15. data/lib/zip/file.rb +12 -12
  16. data/lib/zip/filesystem.rb +17 -13
  17. data/lib/zip/inflater.rb +1 -1
  18. data/lib/zip/input_stream.rb +10 -7
  19. data/lib/zip/ioextras/abstract_input_stream.rb +1 -1
  20. data/lib/zip/ioextras/abstract_output_stream.rb +1 -1
  21. data/lib/zip/output_stream.rb +5 -5
  22. data/lib/zip/pass_thru_decompressor.rb +1 -1
  23. data/lib/zip/streamable_stream.rb +1 -1
  24. data/lib/zip/version.rb +1 -1
  25. data/samples/example_recursive.rb +14 -15
  26. data/samples/gtk_ruby_zip.rb +1 -1
  27. data/samples/qtzip.rb +1 -1
  28. data/samples/zipfind.rb +2 -2
  29. data/test/central_directory_entry_test.rb +1 -1
  30. data/test/data/gpbit3stored.zip +0 -0
  31. data/test/data/path_traversal/Makefile +10 -0
  32. data/test/data/path_traversal/jwilk/README.md +5 -0
  33. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  34. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  35. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  36. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  37. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  38. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  39. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  40. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  41. data/test/data/path_traversal/relative1.zip +0 -0
  42. data/test/data/path_traversal/tuzovakaoff/README.md +3 -0
  43. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  44. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  45. data/test/data/rubycode.zip +0 -0
  46. data/test/errors_test.rb +1 -0
  47. data/test/file_permissions_test.rb +11 -15
  48. data/test/file_test.rb +27 -9
  49. data/test/filesystem/dir_iterator_test.rb +1 -1
  50. data/test/filesystem/directory_test.rb +29 -11
  51. data/test/filesystem/file_mutating_test.rb +3 -4
  52. data/test/filesystem/file_nonmutating_test.rb +31 -31
  53. data/test/filesystem/file_stat_test.rb +4 -4
  54. data/test/gentestfiles.rb +13 -13
  55. data/test/input_stream_test.rb +6 -6
  56. data/test/ioextras/abstract_output_stream_test.rb +2 -2
  57. data/test/path_traversal_test.rb +134 -0
  58. data/test/test_helper.rb +2 -2
  59. data/test/unicode_file_names_and_comments_test.rb +12 -0
  60. data/test/zip64_full_test.rb +2 -2
  61. metadata +95 -49
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1b7ea085db9b27be420d541113214a73ee044c9f
4
- data.tar.gz: ea28ff723bfd70f2e6f7a02f4fe28b805aa4a47e
3
+ metadata.gz: 898367588fc593bddd565ee8626c75cfbcddfce2
4
+ data.tar.gz: 24d90fd344a11d8cf3b8098c459eb2c765e933e7
5
5
  SHA512:
6
- metadata.gz: 121d7129aa37b72da82b32882401b7837c9cface1edf1b8bfb911cd20a55b2ecdacd308de9b7ed0cb6bc0b45d9d974faf28826efe191ddc36d3eb8431f8fe6f0
7
- data.tar.gz: b1ef9770bcd133de33f61642665d511a11aff21aba880cf1226df0c8e1b3602833679384d76bf6877b19567406f7bd9a60de8bd78aded3f303660fbb80b31bb7
6
+ metadata.gz: 4f00c8c74720ba3bf103596601400f57e89d03cdd90b4423debd4c96ed6150a3db0fa8f7407201657cf6a7ee0b2e6586c7a284e1398dd1cf44c523799e1b25be
7
+ data.tar.gz: 3a434114b84d7b109e26aec4821b395ad100efda591ad004656c6b5fd8cdba3740e50c171409c726a9770996e0815ef0324c87063d975024642c6f89ba56377e
data/README.md CHANGED
@@ -52,9 +52,9 @@ Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
52
52
  # Two arguments:
53
53
  # - The name of the file as it will appear in the archive
54
54
  # - The original file, including the path to find it
55
- zipfile.add(filename, folder + '/' + filename)
55
+ zipfile.add(filename, File.join(folder, filename))
56
56
  end
57
- zipfile.get_output_stream("myFile") { |os| os.write "myFile contains just this" }
57
+ zipfile.get_output_stream("myFile") { |f| f.write "myFile contains just this" }
58
58
  end
59
59
  ```
60
60
 
@@ -85,36 +85,36 @@ class ZipFileGenerator
85
85
  def write
86
86
  entries = Dir.entries(@input_dir) - %w(. ..)
87
87
 
88
- ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |io|
89
- write_entries entries, '', io
88
+ ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
89
+ write_entries entries, '', zipfile
90
90
  end
91
91
  end
92
92
 
93
93
  private
94
94
 
95
95
  # A helper method to make the recursion work.
96
- def write_entries(entries, path, io)
96
+ def write_entries(entries, path, zipfile)
97
97
  entries.each do |e|
98
- zip_file_path = path == '' ? e : File.join(path, e)
99
- disk_file_path = File.join(@input_dir, zip_file_path)
98
+ zipfile_path = path == '' ? e : File.join(path, e)
99
+ disk_file_path = File.join(@input_dir, zipfile_path)
100
100
  puts "Deflating #{disk_file_path}"
101
101
 
102
102
  if File.directory? disk_file_path
103
- recursively_deflate_directory(disk_file_path, io, zip_file_path)
103
+ recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
104
104
  else
105
- put_into_archive(disk_file_path, io, zip_file_path)
105
+ put_into_archive(disk_file_path, zipfile, zipfile_path)
106
106
  end
107
107
  end
108
108
  end
109
109
 
110
- def recursively_deflate_directory(disk_file_path, io, zip_file_path)
111
- io.mkdir zip_file_path
110
+ def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
111
+ zipfile.mkdir zipfile_path
112
112
  subdir = Dir.entries(disk_file_path) - %w(. ..)
113
- write_entries subdir, zip_file_path, io
113
+ write_entries subdir, zipfile_path, zipfile
114
114
  end
115
115
 
116
- def put_into_archive(disk_file_path, io, zip_file_path)
117
- io.get_output_stream(zip_file_path) do |f|
116
+ def put_into_archive(disk_file_path, zipfile, zipfile_path)
117
+ zipfile.get_output_stream(zipfile_path) do |f|
118
118
  f.write(File.open(disk_file_path, 'rb').read)
119
119
  end
120
120
  end
@@ -175,9 +175,8 @@ end
175
175
 
176
176
  But there is one exception when it is not working - General Purpose Flag Bit 3.
177
177
 
178
- ```
179
- If bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written. The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure (optionally preceded by a 4-byte signature) immediately after the compressed data
180
- ```
178
+ > If bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written. The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure (optionally preceded by a 4-byte signature) immediately after the compressed data
179
+
181
180
 
182
181
  If `::Zip::InputStream` finds such entry in the zip archive it will raise an exception.
183
182
 
@@ -254,6 +253,14 @@ Zip.default_compression = Zlib::DEFAULT_COMPRESSION
254
253
  ```
255
254
  It defaults to `Zlib::DEFAULT_COMPRESSION`. Possible values are `Zlib::BEST_COMPRESSION`, `Zlib::DEFAULT_COMPRESSION` and `Zlib::NO_COMPRESSION`
256
255
 
256
+ Sometimes file names inside zip contain non-ASCII characters. If you can assume which encoding was used for such names and want to be able to find such entries using `find_entry` then you can force assumed encoding like so:
257
+
258
+ ```ruby
259
+ Zip.force_entry_names_encoding = 'UTF-8'
260
+ ```
261
+
262
+ Allowed encoding names are the same as accepted by `String#force_encoding`
263
+
257
264
  You can set multiple settings at the same time by using a block:
258
265
 
259
266
  ```ruby
data/lib/zip.rb CHANGED
@@ -34,7 +34,15 @@ require 'zip/errors'
34
34
 
35
35
  module Zip
36
36
  extend self
37
- attr_accessor :unicode_names, :on_exists_proc, :continue_on_exists_proc, :sort_entries, :default_compression, :write_zip64_support, :warn_invalid_date, :case_insensitive_match
37
+ attr_accessor :unicode_names,
38
+ :on_exists_proc,
39
+ :continue_on_exists_proc,
40
+ :sort_entries,
41
+ :default_compression,
42
+ :write_zip64_support,
43
+ :warn_invalid_date,
44
+ :case_insensitive_match,
45
+ :force_entry_names_encoding
38
46
 
39
47
  def reset!
40
48
  @_ran_once = false
@@ -96,7 +96,7 @@ module Zip
96
96
  @size_in_bytes = Entry.read_zip_64_long(buf)
97
97
  @cdir_offset = Entry.read_zip_64_long(buf)
98
98
  @zip_64_extensible = buf.slice!(0, buf.bytesize)
99
- raise Error, 'Zip consistency problem while reading eocd structure' unless buf.size == 0
99
+ raise Error, 'Zip consistency problem while reading eocd structure' unless buf.empty?
100
100
  end
101
101
 
102
102
  def read_e_o_c_d(buf) #:nodoc:
@@ -113,7 +113,7 @@ module Zip
113
113
  else
114
114
  buf.read(comment_length)
115
115
  end
116
- raise Error, 'Zip consistency problem while reading eocd structure' unless buf.size == 0
116
+ raise Error, 'Zip consistency problem while reading eocd structure' unless buf.empty?
117
117
  end
118
118
 
119
119
  def read_central_directory_entries(io) #:nodoc:
@@ -130,7 +130,7 @@ module Zip
130
130
 
131
131
  def read_from_stream(io) #:nodoc:
132
132
  buf = start_buf(io)
133
- if self.zip64_file?(buf)
133
+ if zip64_file?(buf)
134
134
  read_64_e_o_c_d(buf)
135
135
  else
136
136
  read_e_o_c_d(buf)
@@ -1,7 +1,6 @@
1
1
  module Zip
2
2
  class Compressor #:nodoc:all
3
- def finish
4
- end
3
+ def finish; end
5
4
  end
6
5
  end
7
6
 
@@ -11,9 +11,9 @@ module Zip
11
11
  VERSION_NEEDED_TO_EXTRACT = 20
12
12
  VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45
13
13
 
14
- FILE_TYPE_FILE = 010
15
- FILE_TYPE_DIR = 004
16
- FILE_TYPE_SYMLINK = 012
14
+ FILE_TYPE_FILE = 0o10
15
+ FILE_TYPE_DIR = 0o04
16
+ FILE_TYPE_SYMLINK = 0o12
17
17
 
18
18
  FSTYPE_FAT = 0
19
19
  FSTYPE_AMIGA = 1
@@ -24,8 +24,7 @@ module Zip
24
24
  ''
25
25
  end
26
26
 
27
- def reset!
28
- end
27
+ def reset!; end
29
28
  end
30
29
 
31
30
  class NullDecrypter < Decrypter
@@ -35,8 +34,7 @@ module Zip
35
34
  data
36
35
  end
37
36
 
38
- def reset!(_header)
39
- end
37
+ def reset!(_header); end
40
38
  end
41
39
  end
42
40
 
@@ -1,5 +1,5 @@
1
1
  module Zip
2
- class Decompressor #:nodoc:all
2
+ class Decompressor #:nodoc:all
3
3
  CHUNK_SIZE = 32_768
4
4
  def initialize(input_stream)
5
5
  super()
@@ -19,7 +19,7 @@ module Zip
19
19
  end
20
20
 
21
21
  def to_binary_dos_date
22
- (day) +
22
+ day +
23
23
  (month << 5) +
24
24
  ((year - 1980) << 9)
25
25
  end
@@ -99,7 +99,7 @@ module Zip
99
99
  end
100
100
 
101
101
  # Dynamic checkers
102
- %w(directory file symlink).each do |k|
102
+ %w[directory file symlink].each do |k|
103
103
  define_method "#{k}?" do
104
104
  file_type_is?(k.to_sym)
105
105
  end
@@ -109,6 +109,17 @@ module Zip
109
109
  @name.end_with?('/')
110
110
  end
111
111
 
112
+ # Is the name a relative path, free of `..` patterns that could lead to
113
+ # path traversal attacks? This does NOT handle symlinks; if the path
114
+ # contains symlinks, this check is NOT enough to guarantee safety.
115
+ def name_safe?
116
+ cleanpath = Pathname.new(@name).cleanpath
117
+ return false unless cleanpath.relative?
118
+ root = ::File::SEPARATOR
119
+ naive_expanded_path = ::File.join(root, cleanpath.to_s)
120
+ cleanpath.expand_path(root).to_s == naive_expanded_path
121
+ end
122
+
112
123
  def local_entry_offset #:nodoc:all
113
124
  local_header_offset + @local_header_size
114
125
  end
@@ -147,14 +158,17 @@ module Zip
147
158
  end
148
159
 
149
160
  # Extracts entry to file dest_path (defaults to @name).
150
- def extract(dest_path = @name, &block)
151
- block ||= proc { ::Zip.on_exists_proc }
152
-
153
- if @name.squeeze('/') =~ /\.{2}(?:\/|\z)/
154
- puts "WARNING: skipped \"../\" path component(s) in #{@name}"
161
+ # NB: The caller is responsible for making sure dest_path is safe, if it
162
+ # is passed.
163
+ def extract(dest_path = nil, &block)
164
+ if dest_path.nil? && !name_safe?
165
+ puts "WARNING: skipped #{@name} as unsafe"
155
166
  return self
156
167
  end
157
168
 
169
+ dest_path ||= @name
170
+ block ||= proc { ::Zip.on_exists_proc }
171
+
158
172
  if directory? || file? || symlink?
159
173
  __send__("create_#{@ftype}", dest_path, &block)
160
174
  else
@@ -239,7 +253,10 @@ module Zip
239
253
  @name = io.read(@name_length)
240
254
  extra = io.read(@extra_length)
241
255
 
242
- @name.gsub!('\\', '/')
256
+ @name.tr!('\\', '/')
257
+ if ::Zip.force_entry_names_encoding
258
+ @name.force_encoding(::Zip.force_entry_names_encoding)
259
+ end
243
260
 
244
261
  if extra && extra.bytesize != @extra_length
245
262
  raise ::Zip::Error, 'Truncated local zip entry header'
@@ -263,8 +280,8 @@ module Zip
263
280
  @time.to_binary_dos_time, # @last_mod_time ,
264
281
  @time.to_binary_dos_date, # @last_mod_date ,
265
282
  @crc,
266
- (zip64 && zip64.compressed_size) ? 0xFFFFFFFF : @compressed_size,
267
- (zip64 && zip64.original_size) ? 0xFFFFFFFF : @size,
283
+ zip64 && zip64.compressed_size ? 0xFFFFFFFF : @compressed_size,
284
+ zip64 && zip64.original_size ? 0xFFFFFFFF : @size,
268
285
  name_size,
269
286
  @extra ? @extra.local_size : 0].pack('VvvvvvVVVvv')
270
287
  end
@@ -308,7 +325,7 @@ module Zip
308
325
  def set_ftype_from_c_dir_entry
309
326
  @ftype = case @fstype
310
327
  when ::Zip::FSTYPE_UNIX
311
- @unix_perms = (@external_file_attributes >> 16) & 07777
328
+ @unix_perms = (@external_file_attributes >> 16) & 0o7777
312
329
  case (@external_file_attributes >> 28)
313
330
  when ::Zip::FILE_TYPE_DIR
314
331
  :directory
@@ -364,6 +381,9 @@ module Zip
364
381
  check_c_dir_entry_signature
365
382
  set_time(@last_mod_date, @last_mod_time)
366
383
  @name = io.read(@name_length)
384
+ if ::Zip.force_entry_names_encoding
385
+ @name.force_encoding(::Zip.force_entry_names_encoding)
386
+ end
367
387
  read_c_dir_extra_field(io)
368
388
  @comment = io.read(@comment_length)
369
389
  check_c_dir_entry_comment_size
@@ -384,14 +404,14 @@ module Zip
384
404
  stat = file_stat(path)
385
405
  @unix_uid = stat.uid
386
406
  @unix_gid = stat.gid
387
- @unix_perms = stat.mode & 07777
407
+ @unix_perms = stat.mode & 0o7777
388
408
  end
389
409
 
390
410
  def set_unix_permissions_on_path(dest_path)
391
411
  # BUG: does not update timestamps into account
392
412
  # ignore setuid/setgid bits by default. honor if @restore_ownership
393
- unix_perms_mask = 01777
394
- unix_perms_mask = 07777 if @restore_ownership
413
+ unix_perms_mask = 0o1777
414
+ unix_perms_mask = 0o7777 if @restore_ownership
395
415
  ::FileUtils.chmod(@unix_perms & unix_perms_mask, dest_path) if @restore_permissions && @unix_perms
396
416
  ::FileUtils.chown(@unix_uid, @unix_gid, dest_path) if @restore_ownership && @unix_uid && @unix_gid && ::Process.egid == 0
397
417
  # File::utimes()
@@ -418,15 +438,15 @@ module Zip
418
438
  @time.to_binary_dos_time, # @last_mod_time ,
419
439
  @time.to_binary_dos_date, # @last_mod_date ,
420
440
  @crc,
421
- (zip64 && zip64.compressed_size) ? 0xFFFFFFFF : @compressed_size,
422
- (zip64 && zip64.original_size) ? 0xFFFFFFFF : @size,
441
+ zip64 && zip64.compressed_size ? 0xFFFFFFFF : @compressed_size,
442
+ zip64 && zip64.original_size ? 0xFFFFFFFF : @size,
423
443
  name_size,
424
444
  @extra ? @extra.c_dir_size : 0,
425
445
  comment_size,
426
- (zip64 && zip64.disk_start_number) ? 0xFFFF : 0, # disk number start
446
+ zip64 && zip64.disk_start_number ? 0xFFFF : 0, # disk number start
427
447
  @internal_file_attributes, # file type (binary=0, text=1)
428
448
  @external_file_attributes, # native filesystem attributes
429
- (zip64 && zip64.relative_header_offset) ? 0xFFFFFFFF : @local_header_offset,
449
+ zip64 && zip64.relative_header_offset ? 0xFFFFFFFF : @local_header_offset,
430
450
  @name,
431
451
  @extra,
432
452
  @comment
@@ -439,18 +459,18 @@ module Zip
439
459
  when ::Zip::FSTYPE_UNIX
440
460
  ft = case @ftype
441
461
  when :file
442
- @unix_perms ||= 0644
462
+ @unix_perms ||= 0o644
443
463
  ::Zip::FILE_TYPE_FILE
444
464
  when :directory
445
- @unix_perms ||= 0755
465
+ @unix_perms ||= 0o755
446
466
  ::Zip::FILE_TYPE_DIR
447
467
  when :symlink
448
- @unix_perms ||= 0755
468
+ @unix_perms ||= 0o755
449
469
  ::Zip::FILE_TYPE_SYMLINK
450
470
  end
451
471
 
452
472
  unless ft.nil?
453
- @external_file_attributes = (ft << 12 | (@unix_perms & 07777)) << 16
473
+ @external_file_attributes = (ft << 12 | (@unix_perms & 0o7777)) << 16
454
474
  end
455
475
  end
456
476
 
@@ -464,7 +484,7 @@ module Zip
464
484
  def ==(other)
465
485
  return false unless other.class == self.class
466
486
  # Compares contents of local entry and exposed fields
467
- keys_equal = %w(compression_method crc compressed_size size name extra filepath).all? do |k|
487
+ keys_equal = %w[compression_method crc compressed_size size name extra filepath].all? do |k|
468
488
  other.__send__(k.to_sym) == __send__(k.to_sym)
469
489
  end
470
490
  keys_equal && time.dos_equals(other.time)
@@ -494,7 +514,7 @@ module Zip
494
514
  end
495
515
  else
496
516
  zis = ::Zip::InputStream.new(@zipfile, local_header_offset)
497
- zis.instance_variable_set(:@internal, true)
517
+ zis.instance_variable_set(:@complete_entry, self)
498
518
  zis.get_next_entry
499
519
  if block_given?
500
520
  begin
@@ -607,32 +627,9 @@ module Zip
607
627
 
608
628
  # BUG: create_symlink() does not use &block
609
629
  def create_symlink(dest_path)
610
- stat = nil
611
- begin
612
- stat = ::File.lstat(dest_path)
613
- rescue Errno::ENOENT
614
- end
615
-
616
- io = get_input_stream
617
- linkto = io.read
618
-
619
- if stat
620
- if stat.symlink?
621
- if ::File.readlink(dest_path) == linkto
622
- return
623
- else
624
- raise ::Zip::DestinationFileExistsError,
625
- "Cannot create symlink '#{dest_path}'. " \
626
- 'A symlink already exists with that name'
627
- end
628
- else
629
- raise ::Zip::DestinationFileExistsError,
630
- "Cannot create symlink '#{dest_path}'. " \
631
- 'A file already exists with that name'
632
- end
633
- end
634
-
635
- ::File.symlink(linkto, dest_path)
630
+ # TODO: Symlinks pose security challenges. Symlink support temporarily
631
+ # removed in view of https://github.com/rubyzip/rubyzip/issues/369 .
632
+ puts "WARNING: skipped symlink #{dest_path}"
636
633
  end
637
634
 
638
635
  # apply missing data from the zip64 extra information field, if present
@@ -5,7 +5,7 @@ module Zip
5
5
 
6
6
  def initialize(an_enumerable = [])
7
7
  super()
8
- @entry_set = {}
8
+ @entry_set = {}
9
9
  an_enumerable.each { |o| push(o) }
10
10
  end
11
11
 
@@ -33,9 +33,9 @@ module Zip
33
33
  entry if @entry_set.delete(to_key(entry))
34
34
  end
35
35
 
36
- def each(&block)
36
+ def each
37
37
  @entry_set = sorted_entries.dup.each do |_, value|
38
- block.call(value)
38
+ yield(value)
39
39
  end
40
40
  end
41
41
 
@@ -8,7 +8,7 @@ module Zip
8
8
 
9
9
  def extra_field_type_exist(binstr, id, len, i)
10
10
  field_name = ID_MAP[id].name
11
- if self.member?(field_name)
11
+ if member?(field_name)
12
12
  self[field_name].merge(binstr[i, len + 4])
13
13
  else
14
14
  field_obj = ID_MAP[id].new(binstr[i, len + 4])
@@ -1,7 +1,7 @@
1
1
  module Zip
2
2
  class ExtraField::Generic
3
3
  def self.register_map
4
- if self.const_defined?(:HEADER_ID)
4
+ if const_defined?(:HEADER_ID)
5
5
  ::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
6
6
  end
7
7
  end
@@ -6,8 +6,7 @@ module Zip
6
6
  HEADER_ID = ['9999'].pack('H*') # this ID is used by other libraries such as .NET's Ionic.zip
7
7
  register_map
8
8
 
9
- def initialize(_binstr = nil)
10
- end
9
+ def initialize(_binstr = nil); end
11
10
 
12
11
  def pack_for_local
13
12
  "\x00" * 16