rubyzip 1.1.7 → 1.2.1

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +75 -40
  3. data/Rakefile +3 -4
  4. data/lib/zip.rb +3 -5
  5. data/lib/zip/central_directory.rb +7 -7
  6. data/lib/zip/compressor.rb +0 -0
  7. data/lib/zip/constants.rb +2 -2
  8. data/lib/zip/crypto/null_encryption.rb +3 -3
  9. data/lib/zip/crypto/traditional_encryption.rb +5 -5
  10. data/lib/zip/decompressor.rb +2 -2
  11. data/lib/zip/deflater.rb +8 -6
  12. data/lib/zip/dos_time.rb +4 -5
  13. data/lib/zip/entry.rb +75 -81
  14. data/lib/zip/entry_set.rb +11 -11
  15. data/lib/zip/errors.rb +1 -0
  16. data/lib/zip/extra_field.rb +6 -6
  17. data/lib/zip/extra_field/generic.rb +7 -7
  18. data/lib/zip/extra_field/ntfs.rb +14 -16
  19. data/lib/zip/extra_field/old_unix.rb +9 -10
  20. data/lib/zip/extra_field/universal_time.rb +14 -14
  21. data/lib/zip/extra_field/unix.rb +8 -9
  22. data/lib/zip/extra_field/zip64.rb +12 -11
  23. data/lib/zip/extra_field/zip64_placeholder.rb +1 -1
  24. data/lib/zip/file.rb +47 -60
  25. data/lib/zip/filesystem.rb +132 -135
  26. data/lib/zip/inflater.rb +3 -3
  27. data/lib/zip/input_stream.rb +13 -7
  28. data/lib/zip/ioextras.rb +1 -3
  29. data/lib/zip/ioextras/abstract_input_stream.rb +5 -9
  30. data/lib/zip/ioextras/abstract_output_stream.rb +2 -4
  31. data/lib/zip/null_compressor.rb +2 -2
  32. data/lib/zip/null_decompressor.rb +3 -3
  33. data/lib/zip/null_input_stream.rb +0 -0
  34. data/lib/zip/output_stream.rb +8 -9
  35. data/lib/zip/pass_thru_compressor.rb +4 -4
  36. data/lib/zip/pass_thru_decompressor.rb +2 -3
  37. data/lib/zip/streamable_directory.rb +2 -2
  38. data/lib/zip/streamable_stream.rb +2 -2
  39. data/lib/zip/version.rb +1 -1
  40. data/samples/example.rb +29 -39
  41. data/samples/example_filesystem.rb +16 -18
  42. data/samples/example_recursive.rb +32 -25
  43. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +23 -25
  44. data/samples/qtzip.rb +17 -26
  45. data/samples/write_simple.rb +12 -13
  46. data/samples/zipfind.rb +24 -32
  47. data/test/basic_zip_file_test.rb +11 -15
  48. data/test/case_sensitivity_test.rb +69 -0
  49. data/test/central_directory_entry_test.rb +32 -36
  50. data/test/central_directory_test.rb +46 -50
  51. data/test/crypto/null_encryption_test.rb +8 -4
  52. data/test/crypto/traditional_encryption_test.rb +5 -5
  53. data/test/data/notzippedruby.rb +1 -1
  54. data/test/data/oddExtraField.zip +0 -0
  55. data/test/data/test.xls +0 -0
  56. data/test/deflater_test.rb +10 -12
  57. data/test/encryption_test.rb +2 -2
  58. data/test/entry_set_test.rb +50 -25
  59. data/test/entry_test.rb +76 -87
  60. data/test/errors_test.rb +0 -2
  61. data/test/extra_field_test.rb +19 -21
  62. data/test/file_extract_directory_test.rb +12 -14
  63. data/test/file_extract_test.rb +33 -40
  64. data/test/file_permissions_test.rb +69 -0
  65. data/test/file_split_test.rb +24 -27
  66. data/test/file_test.rb +196 -172
  67. data/test/filesystem/dir_iterator_test.rb +13 -17
  68. data/test/filesystem/directory_test.rb +80 -90
  69. data/test/filesystem/file_mutating_test.rb +51 -63
  70. data/test/filesystem/file_nonmutating_test.rb +222 -228
  71. data/test/filesystem/file_stat_test.rb +17 -19
  72. data/test/gentestfiles.rb +47 -55
  73. data/test/inflater_test.rb +1 -1
  74. data/test/input_stream_test.rb +46 -34
  75. data/test/ioextras/abstract_input_stream_test.rb +22 -23
  76. data/test/ioextras/abstract_output_stream_test.rb +32 -32
  77. data/test/ioextras/fake_io_test.rb +1 -1
  78. data/test/local_entry_test.rb +36 -38
  79. data/test/output_stream_test.rb +20 -21
  80. data/test/pass_thru_compressor_test.rb +5 -6
  81. data/test/pass_thru_decompressor_test.rb +0 -1
  82. data/test/samples/example_recursive_test.rb +37 -0
  83. data/test/settings_test.rb +18 -15
  84. data/test/test_helper.rb +50 -44
  85. data/test/unicode_file_names_and_comments_test.rb +5 -7
  86. data/test/zip64_full_test.rb +9 -11
  87. data/test/zip64_support_test.rb +0 -1
  88. metadata +14 -32
@@ -1,7 +1,6 @@
1
1
  module Zip
2
2
  class DOSTime < Time #:nodoc:all
3
-
4
- #MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
3
+ # MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
5
4
 
6
5
  # Register CX, the Time:
7
6
  # Bits 0-4 2 second increments (0-29)
@@ -14,7 +13,7 @@ module Zip
14
13
  # bits 9-15 year (four digit year minus 1980)
15
14
 
16
15
  def to_binary_dos_time
17
- (sec/2) +
16
+ (sec / 2) +
18
17
  (min << 5) +
19
18
  (hour << 11)
20
19
  end
@@ -27,7 +26,7 @@ module Zip
27
26
 
28
27
  # Dos time is only stored with two seconds accuracy
29
28
  def dos_equals(other)
30
- to_i/2 == other.to_i/2
29
+ to_i / 2 == other.to_i / 2
31
30
  end
32
31
 
33
32
  def self.parse_binary_dos_format(binaryDosDate, binaryDosTime)
@@ -38,7 +37,7 @@ module Zip
38
37
  month = (0b111100000 & binaryDosDate) >> 5
39
38
  year = ((0b1111111000000000 & binaryDosDate) >> 9) + 1980
40
39
  begin
41
- self.local(year, month, day, hour, minute, second)
40
+ local(year, month, day, hour, minute, second)
42
41
  end
43
42
  end
44
43
  end
@@ -7,6 +7,7 @@ module Zip
7
7
 
8
8
  attr_accessor :comment, :compressed_size, :crc, :extra, :compression_method,
9
9
  :name, :size, :local_header_offset, :zipfile, :fstype, :external_file_attributes,
10
+ :internal_file_attributes,
10
11
  :gp_flags, :header_signature, :follow_symlinks,
11
12
  :restore_times, :restore_permissions, :restore_ownership,
12
13
  :unix_uid, :unix_gid, :unix_perms,
@@ -39,15 +40,14 @@ module Zip
39
40
  @unix_uid = nil
40
41
  @unix_gid = nil
41
42
  @unix_perms = nil
42
- #@posix_acl = nil
43
- #@ntfs_acl = nil
43
+ # @posix_acl = nil
44
+ # @ntfs_acl = nil
44
45
  @dirty = false
45
46
  end
46
47
 
47
48
  def check_name(name)
48
- if name.start_with?('/')
49
- raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
50
- end
49
+ return unless name.start_with?('/')
50
+ raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
51
51
  end
52
52
 
53
53
  def initialize(*args)
@@ -68,7 +68,7 @@ module Zip
68
68
  @time = args[8] || ::Zip::DOSTime.now
69
69
 
70
70
  @ftype = name_is_directory? ? :directory : :file
71
- @extra = ::Zip::ExtraField.new(@extra.to_s) unless ::Zip::ExtraField === @extra
71
+ @extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.is_a?(::Zip::ExtraField)
72
72
  end
73
73
 
74
74
  def time
@@ -83,7 +83,7 @@ module Zip
83
83
  end
84
84
  end
85
85
 
86
- alias :mtime :time
86
+ alias mtime time
87
87
 
88
88
  def time=(value)
89
89
  unless @extra.member?('UniversalTime') || @extra.member?('NTFS')
@@ -94,7 +94,7 @@ module Zip
94
94
  end
95
95
 
96
96
  def file_type_is?(type)
97
- raise InternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
97
+ raise InternalError, "current filetype is unknown: #{inspect}" unless @ftype
98
98
  @ftype == type
99
99
  end
100
100
 
@@ -143,17 +143,22 @@ module Zip
143
143
  end
144
144
 
145
145
  def next_header_offset #:nodoc:all
146
- local_entry_offset + self.compressed_size + data_descriptor_size
146
+ local_entry_offset + compressed_size + data_descriptor_size
147
147
  end
148
148
 
149
149
  # Extracts entry to file dest_path (defaults to @name).
150
150
  def extract(dest_path = @name, &block)
151
151
  block ||= proc { ::Zip.on_exists_proc }
152
152
 
153
+ if @name.squeeze('/') =~ /\.{2}(?:\/|\z)/
154
+ puts "WARNING: skipped \"../\" path component(s) in #{@name}"
155
+ return self
156
+ end
157
+
153
158
  if directory? || file? || symlink?
154
- self.__send__("create_#{@ftype}", dest_path, &block)
159
+ __send__("create_#{@ftype}", dest_path, &block)
155
160
  else
156
- raise RuntimeError, "unknown file type #{self.inspect}"
161
+ raise "unknown file type #{inspect}"
157
162
  end
158
163
 
159
164
  self
@@ -163,8 +168,6 @@ module Zip
163
168
  @name
164
169
  end
165
170
 
166
- protected
167
-
168
171
  class << self
169
172
  def read_zip_short(io) # :nodoc:
170
173
  io.read(2).unpack('v')[0]
@@ -179,11 +182,11 @@ module Zip
179
182
  end
180
183
 
181
184
  def read_c_dir_entry(io) #:nodoc:all
182
- path = if io.is_a?(::IO)
183
- io.path
184
- else
185
- io
186
- end
185
+ path = if io.respond_to?(:path)
186
+ io.path
187
+ else
188
+ io
189
+ end
187
190
  entry = new(path)
188
191
  entry.read_c_dir_entry(io)
189
192
  entry
@@ -192,13 +195,12 @@ module Zip
192
195
  end
193
196
 
194
197
  def read_local_entry(io)
195
- entry = self.new(io)
198
+ entry = new(io)
196
199
  entry.read_local_entry(io)
197
200
  entry
198
201
  rescue Error
199
202
  nil
200
203
  end
201
-
202
204
  end
203
205
 
204
206
  public
@@ -221,10 +223,10 @@ module Zip
221
223
  def read_local_entry(io) #:nodoc:all
222
224
  @local_header_offset = io.tell
223
225
 
224
- static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH)
226
+ static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
225
227
 
226
228
  unless static_sized_fields_buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
227
- raise Error, "Premature end of file. Not enough data for zip entry local header"
229
+ raise Error, 'Premature end of file. Not enough data for zip entry local header'
228
230
  end
229
231
 
230
232
  unpack_local_entry(static_sized_fields_buf)
@@ -240,10 +242,10 @@ module Zip
240
242
  @name.gsub!('\\', '/')
241
243
 
242
244
  if extra && extra.bytesize != @extra_length
243
- raise ::Zip::Error, "Truncated local zip entry header"
245
+ raise ::Zip::Error, 'Truncated local zip entry header'
244
246
  else
245
- if ::Zip::ExtraField === @extra
246
- @extra.merge(extra)
247
+ if @extra.is_a?(::Zip::ExtraField)
248
+ @extra.merge(extra) if extra
247
249
  else
248
250
  @extra = ::Zip::ExtraField.new(extra)
249
251
  end
@@ -315,8 +317,8 @@ module Zip
315
317
  when ::Zip::FILE_TYPE_SYMLINK
316
318
  :symlink
317
319
  else
318
- #best case guess for whether it is a file or not
319
- #Otherwise this would be set to unknown and that entry would never be able to extracted
320
+ # best case guess for whether it is a file or not
321
+ # Otherwise this would be set to unknown and that entry would never be able to extracted
320
322
  if name_is_directory?
321
323
  :directory
322
324
  else
@@ -333,21 +335,18 @@ module Zip
333
335
  end
334
336
 
335
337
  def check_c_dir_entry_static_header_length(buf)
336
- unless buf.bytesize == ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
337
- raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
338
- end
338
+ return if buf.bytesize == ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
339
+ raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
339
340
  end
340
341
 
341
342
  def check_c_dir_entry_signature
342
- unless header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
343
- raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
344
- end
343
+ return if header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
344
+ raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
345
345
  end
346
346
 
347
347
  def check_c_dir_entry_comment_size
348
- unless @comment && @comment.bytesize == @comment_length
349
- raise ::Zip::Error, "Truncated cdir zip entry header"
350
- end
348
+ return if @comment && @comment.bytesize == @comment_length
349
+ raise ::Zip::Error, 'Truncated cdir zip entry header'
351
350
  end
352
351
 
353
352
  def read_c_dir_extra_field(io)
@@ -364,7 +363,7 @@ module Zip
364
363
  unpack_c_dir_entry(static_sized_fields_buf)
365
364
  check_c_dir_entry_signature
366
365
  set_time(@last_mod_date, @last_mod_time)
367
- @name = io.read(@name_length).tr('\\', '/')
366
+ @name = io.read(@name_length)
368
367
  read_c_dir_extra_field(io)
369
368
  @comment = io.read(@comment_length)
370
369
  check_c_dir_entry_comment_size
@@ -374,19 +373,18 @@ module Zip
374
373
 
375
374
  def file_stat(path) # :nodoc:
376
375
  if @follow_symlinks
377
- ::File::stat(path)
376
+ ::File.stat(path)
378
377
  else
379
- ::File::lstat(path)
378
+ ::File.lstat(path)
380
379
  end
381
380
  end
382
381
 
383
382
  def get_extra_attributes_from_path(path) # :nodoc:
384
- unless Zip::RUNNING_ON_WINDOWS
385
- stat = file_stat(path)
386
- @unix_uid = stat.uid
387
- @unix_gid = stat.gid
388
- @unix_perms = stat.mode & 07777
389
- end
383
+ return if Zip::RUNNING_ON_WINDOWS
384
+ stat = file_stat(path)
385
+ @unix_uid = stat.uid
386
+ @unix_gid = stat.gid
387
+ @unix_perms = stat.mode & 07777
390
388
  end
391
389
 
392
390
  def set_unix_permissions_on_path(dest_path)
@@ -400,7 +398,7 @@ module Zip
400
398
  end
401
399
 
402
400
  def set_extra_attributes_on_path(dest_path) # :nodoc:
403
- return unless (file? || directory?)
401
+ return unless file? || directory?
404
402
 
405
403
  case @fstype
406
404
  when ::Zip::FSTYPE_UNIX
@@ -467,13 +465,13 @@ module Zip
467
465
  return false unless other.class == self.class
468
466
  # Compares contents of local entry and exposed fields
469
467
  keys_equal = %w(compression_method crc compressed_size size name extra filepath).all? do |k|
470
- other.__send__(k.to_sym) == self.__send__(k.to_sym)
468
+ other.__send__(k.to_sym) == __send__(k.to_sym)
471
469
  end
472
- keys_equal && self.time.dos_equals(other.time)
470
+ keys_equal && time.dos_equals(other.time)
473
471
  end
474
472
 
475
- def <=> (other)
476
- self.to_s <=> other.to_s
473
+ def <=>(other)
474
+ to_s <=> other.to_s
477
475
  end
478
476
 
479
477
  # Returns an IO like object for the given ZipEntry.
@@ -496,6 +494,7 @@ module Zip
496
494
  end
497
495
  else
498
496
  zis = ::Zip::InputStream.new(@zipfile, local_header_offset)
497
+ zis.instance_variable_set(:@internal, true)
499
498
  zis.get_next_entry
500
499
  if block_given?
501
500
  begin
@@ -515,8 +514,8 @@ module Zip
515
514
  when 'file'
516
515
  if name_is_directory?
517
516
  raise ArgumentError,
518
- "entry name '#{newEntry}' indicates directory entry, but "+
519
- "'#{src_path}' is not a directory"
517
+ "entry name '#{newEntry}' indicates directory entry, but " \
518
+ "'#{src_path}' is not a directory"
520
519
  end
521
520
  :file
522
521
  when 'directory'
@@ -525,12 +524,12 @@ module Zip
525
524
  when 'link'
526
525
  if name_is_directory?
527
526
  raise ArgumentError,
528
- "entry name '#{newEntry}' indicates directory entry, but "+
529
- "'#{src_path}' is not a directory"
527
+ "entry name '#{newEntry}' indicates directory entry, but " \
528
+ "'#{src_path}' is not a directory"
530
529
  end
531
530
  :symlink
532
531
  else
533
- raise RuntimeError, "unknown file type: #{src_path.inspect} #{stat.inspect}"
532
+ raise "unknown file type: #{src_path.inspect} #{stat.inspect}"
534
533
  end
535
534
 
536
535
  @filepath = src_path
@@ -541,7 +540,7 @@ module Zip
541
540
  if @ftype == :directory
542
541
  zip_output_stream.put_next_entry(self, nil, nil, ::Zip::Entry::STORED)
543
542
  elsif @filepath
544
- zip_output_stream.put_next_entry(self, nil, nil, self.compression_method || ::Zip::Entry::DEFLATED)
543
+ zip_output_stream.put_next_entry(self, nil, nil, compression_method || ::Zip::Entry::DEFLATED)
545
544
  get_input_stream { |is| ::Zip::IOExtras.copy_stream(zip_output_stream, is) }
546
545
  else
547
546
  zip_output_stream.copy_raw_entry(self)
@@ -551,14 +550,14 @@ module Zip
551
550
  def parent_as_string
552
551
  entry_name = name.chomp('/')
553
552
  slash_index = entry_name.rindex('/')
554
- slash_index ? entry_name.slice(0, slash_index+1) : nil
553
+ slash_index ? entry_name.slice(0, slash_index + 1) : nil
555
554
  end
556
555
 
557
556
  def get_raw_input_stream(&block)
558
- if @zipfile.is_a?(::IO) || @zipfile.is_a?(::StringIO)
557
+ if @zipfile.respond_to?(:seek) && @zipfile.respond_to?(:read)
559
558
  yield @zipfile
560
559
  else
561
- ::File.open(@zipfile, "rb", &block)
560
+ ::File.open(@zipfile, 'rb', &block)
562
561
  end
563
562
  end
564
563
 
@@ -571,20 +570,20 @@ module Zip
571
570
  def set_time(binary_dos_date, binary_dos_time)
572
571
  @time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
573
572
  rescue ArgumentError
574
- puts "Invalid date/time in zip entry" if ::Zip.warn_invalid_date
573
+ warn 'Invalid date/time in zip entry' if ::Zip.warn_invalid_date
575
574
  end
576
575
 
577
- def create_file(dest_path, continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
576
+ def create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
578
577
  if ::File.exist?(dest_path) && !yield(self, dest_path)
579
578
  raise ::Zip::DestinationFileExistsError,
580
579
  "Destination '#{dest_path}' already exists"
581
580
  end
582
- ::File.open(dest_path, "wb") do |os|
581
+ ::File.open(dest_path, 'wb') do |os|
583
582
  get_input_stream do |is|
584
583
  set_extra_attributes_on_path(dest_path)
585
584
 
586
585
  buf = ''
587
- while buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf)
586
+ while (buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf))
588
587
  os << buf
589
588
  end
590
589
  end
@@ -595,11 +594,11 @@ module Zip
595
594
  return if ::File.directory?(dest_path)
596
595
  if ::File.exist?(dest_path)
597
596
  if block_given? && yield(self, dest_path)
598
- ::FileUtils::rm_f dest_path
597
+ ::FileUtils.rm_f dest_path
599
598
  else
600
599
  raise ::Zip::DestinationFileExistsError,
601
- "Cannot create directory '#{dest_path}'. "+
602
- "A file already exists with that name"
600
+ "Cannot create directory '#{dest_path}'. " \
601
+ 'A file already exists with that name'
603
602
  end
604
603
  end
605
604
  ::FileUtils.mkdir_p(dest_path)
@@ -623,13 +622,13 @@ module Zip
623
622
  return
624
623
  else
625
624
  raise ::Zip::DestinationFileExistsError,
626
- "Cannot create symlink '#{dest_path}'. "+
627
- "A symlink already exists with that name"
625
+ "Cannot create symlink '#{dest_path}'. " \
626
+ 'A symlink already exists with that name'
628
627
  end
629
628
  else
630
629
  raise ::Zip::DestinationFileExistsError,
631
- "Cannot create symlink '#{dest_path}'. "+
632
- "A file already exists with that name"
630
+ "Cannot create symlink '#{dest_path}'. " \
631
+ 'A file already exists with that name'
633
632
  end
634
633
  end
635
634
 
@@ -639,12 +638,11 @@ module Zip
639
638
  # apply missing data from the zip64 extra information field, if present
640
639
  # (required when file sizes exceed 2**32, but can be used for all files)
641
640
  def parse_zip64_extra(for_local_header) #:nodoc:all
642
- if zip64 = @extra['Zip64']
643
- if for_local_header
644
- @size, @compressed_size = zip64.parse(@size, @compressed_size)
645
- else
646
- @size, @compressed_size, @local_header_offset = zip64.parse(@size, @compressed_size, @local_header_offset)
647
- end
641
+ return if @extra['Zip64'].nil?
642
+ if for_local_header
643
+ @size, @compressed_size = @extra['Zip64'].parse(@size, @compressed_size)
644
+ else
645
+ @size, @compressed_size, @local_header_offset = @extra['Zip64'].parse(@size, @compressed_size, @local_header_offset)
648
646
  end
649
647
  end
650
648
 
@@ -656,10 +654,7 @@ module Zip
656
654
  def prep_zip64_extra(for_local_header) #:nodoc:all
657
655
  return unless ::Zip.write_zip64_support
658
656
  need_zip64 = @size >= 0xFFFFFFFF || @compressed_size >= 0xFFFFFFFF
659
- unless for_local_header
660
- need_zip64 ||= @local_header_offset >= 0xFFFFFFFF
661
- end
662
-
657
+ need_zip64 ||= @local_header_offset >= 0xFFFFFFFF unless for_local_header
663
658
  if need_zip64
664
659
  @version_needed_to_extract = VERSION_NEEDED_TO_EXTRACT_ZIP64
665
660
  @extra.delete('Zip64Placeholder')
@@ -687,7 +682,6 @@ module Zip
687
682
  end
688
683
  end
689
684
  end
690
-
691
685
  end
692
686
  end
693
687
 
@@ -18,23 +18,19 @@ module Zip
18
18
  end
19
19
 
20
20
  def <<(entry)
21
- @entry_set[to_key(entry)] = entry
21
+ @entry_set[to_key(entry)] = entry if entry
22
22
  end
23
23
 
24
- alias :push :<<
24
+ alias push <<
25
25
 
26
26
  def size
27
27
  @entry_set.size
28
28
  end
29
29
 
30
- alias :length :size
30
+ alias length size
31
31
 
32
32
  def delete(entry)
33
- if @entry_set.delete(to_key(entry))
34
- entry
35
- else
36
- nil
37
- end
33
+ entry if @entry_set.delete(to_key(entry))
38
34
  end
39
35
 
40
36
  def each(&block)
@@ -49,7 +45,7 @@ module Zip
49
45
 
50
46
  # deep clone
51
47
  def dup
52
- EntrySet.new(@entry_set.map { |key, value| value.dup })
48
+ EntrySet.new(@entry_set.values.map(&:dup))
53
49
  end
54
50
 
55
51
  def ==(other)
@@ -61,7 +57,7 @@ module Zip
61
57
  @entry_set[to_key(entry.parent_as_string)]
62
58
  end
63
59
 
64
- def glob(pattern, flags = ::File::FNM_PATHNAME|::File::FNM_DOTMATCH)
60
+ def glob(pattern, flags = ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH | ::File::FNM_EXTGLOB)
65
61
  entries.map do |entry|
66
62
  next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
67
63
  yield(entry) if block_given?
@@ -70,13 +66,17 @@ module Zip
70
66
  end
71
67
 
72
68
  protected
69
+
73
70
  def sorted_entries
74
71
  ::Zip.sort_entries ? Hash[@entry_set.sort] : @entry_set
75
72
  end
76
73
 
77
74
  private
75
+
78
76
  def to_key(entry)
79
- entry.to_s.chomp('/')
77
+ k = entry.to_s.chomp('/')
78
+ k.downcase! if ::Zip.case_insensitive_match
79
+ k
80
80
  end
81
81
  end
82
82
  end