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
@@ -5,6 +5,7 @@ module Zip
5
5
  class CompressionMethodError < Error; end
6
6
  class EntryNameError < Error; end
7
7
  class InternalError < Error; end
8
+ class GPFBit3Error < Error; end
8
9
 
9
10
  # Backwards compatibility with v1 (delete in v2)
10
11
  ZipError = Error
@@ -3,7 +3,7 @@ module Zip
3
3
  ID_MAP = {}
4
4
 
5
5
  def initialize(binstr = nil)
6
- binstr and merge(binstr)
6
+ merge(binstr) if binstr
7
7
  end
8
8
 
9
9
  def extra_field_type_exist(binstr, id, len, i)
@@ -51,7 +51,7 @@ module Zip
51
51
  end
52
52
 
53
53
  def create(name)
54
- unless field_class = ID_MAP.values.find { |k| k.name == name }
54
+ unless (field_class = ID_MAP.values.find { |k| k.name == name })
55
55
  raise Error, "Unknown extra field '#{name}'"
56
56
  end
57
57
  self[name] = field_class.new
@@ -61,7 +61,7 @@ module Zip
61
61
  # does not prevent known fields from being read back in
62
62
  def ordered_values
63
63
  result = []
64
- self.each { |k,v| k == 'Unknown' ? result.push(v) : result.unshift(v) }
64
+ each { |k, v| k == 'Unknown' ? result.push(v) : result.unshift(v) }
65
65
  result
66
66
  end
67
67
 
@@ -69,7 +69,7 @@ module Zip
69
69
  ordered_values.map! { |v| v.to_local_bin.force_encoding('BINARY') }.join
70
70
  end
71
71
 
72
- alias :to_s :to_local_bin
72
+ alias to_s to_local_bin
73
73
 
74
74
  def to_c_dir_bin
75
75
  ordered_values.map! { |v| v.to_c_dir_bin.force_encoding('BINARY') }.join
@@ -83,8 +83,8 @@ module Zip
83
83
  to_local_bin.bytesize
84
84
  end
85
85
 
86
- alias :length :local_size
87
- alias :size :local_size
86
+ alias length local_size
87
+ alias size local_size
88
88
  end
89
89
  end
90
90
 
@@ -2,12 +2,12 @@ module Zip
2
2
  class ExtraField::Generic
3
3
  def self.register_map
4
4
  if self.const_defined?(:HEADER_ID)
5
- ::Zip::ExtraField::ID_MAP[self.const_get(:HEADER_ID)] = self
5
+ ::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
6
6
  end
7
7
  end
8
8
 
9
9
  def self.name
10
- @name ||= self.to_s.split("::")[-1]
10
+ @name ||= to_s.split('::')[-1]
11
11
  end
12
12
 
13
13
  # return field [size, content] or false
@@ -16,28 +16,28 @@ module Zip
16
16
  # If nil, start with empty.
17
17
  return false
18
18
  elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
19
- $stderr.puts "Warning: weired extra feild header ID. skip parsing"
19
+ $stderr.puts 'Warning: weired extra feild header ID. skip parsing'
20
20
  return false
21
21
  end
22
- [binstr[2, 2].unpack("v")[0], binstr[4..-1]]
22
+ [binstr[2, 2].unpack('v')[0], binstr[4..-1]]
23
23
  end
24
24
 
25
25
  def ==(other)
26
26
  return false if self.class != other.class
27
27
  each do |k, v|
28
- v != other[k] and return false
28
+ return false if v != other[k]
29
29
  end
30
30
  true
31
31
  end
32
32
 
33
33
  def to_local_bin
34
34
  s = pack_for_local
35
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack("v") << s
35
+ self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
36
36
  end
37
37
 
38
38
  def to_c_dir_bin
39
39
  s = pack_for_c_dir
40
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack("v") << s
40
+ self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
41
41
  end
42
42
  end
43
43
  end
@@ -5,14 +5,14 @@ module Zip
5
5
  HEADER_ID = [0x000A].pack('v')
6
6
  register_map
7
7
 
8
- WINDOWS_TICK = 10000000.0
9
- SEC_TO_UNIX_EPOCH = 11644473600
8
+ WINDOWS_TICK = 10_000_000.0
9
+ SEC_TO_UNIX_EPOCH = 11_644_473_600
10
10
 
11
11
  def initialize(binstr = nil)
12
12
  @ctime = nil
13
13
  @mtime = nil
14
14
  @atime = nil
15
- binstr and merge(binstr)
15
+ binstr && merge(binstr)
16
16
  end
17
17
 
18
18
  attr_accessor :atime, :ctime, :mtime
@@ -20,18 +20,17 @@ module Zip
20
20
  def merge(binstr)
21
21
  return if binstr.empty?
22
22
  size, content = initial_parse(binstr)
23
- (size && content) or return
23
+ (size && content) || return
24
24
 
25
25
  content = content[4..-1]
26
26
  tags = parse_tags(content)
27
27
 
28
28
  tag1 = tags[1]
29
- if tag1
30
- ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack("Q<Q<Q<")
31
- ntfs_mtime and @mtime ||= from_ntfs_time(ntfs_mtime)
32
- ntfs_atime and @atime ||= from_ntfs_time(ntfs_atime)
33
- ntfs_ctime and @ctime ||= from_ntfs_time(ntfs_ctime)
34
- end
29
+ return unless tag1
30
+ ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
31
+ ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
32
+ ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
33
+ ntfs_ctime && @ctime ||= from_ntfs_time(ntfs_ctime)
35
34
  end
36
35
 
37
36
  def ==(other)
@@ -48,16 +47,14 @@ module Zip
48
47
  # But 7-zip for Windows only stores at central dir
49
48
  def pack_for_c_dir
50
49
  # reserved 0 and tag 1
51
- s = [0, 1].pack("Vv")
50
+ s = [0, 1].pack('Vv')
52
51
 
53
52
  tag1 = ''.force_encoding(Encoding::BINARY)
54
53
  if @mtime
55
54
  tag1 << [to_ntfs_time(@mtime)].pack('Q<')
56
55
  if @atime
57
56
  tag1 << [to_ntfs_time(@atime)].pack('Q<')
58
- if @ctime
59
- tag1 << [to_ntfs_time(@ctime)].pack('Q<')
60
- end
57
+ tag1 << [to_ntfs_time(@ctime)].pack('Q<') if @ctime
61
58
  end
62
59
  end
63
60
  s << [tag1.bytesize].pack('v') << tag1
@@ -65,11 +62,12 @@ module Zip
65
62
  end
66
63
 
67
64
  private
65
+
68
66
  def parse_tags(content)
69
67
  return {} if content.nil?
70
68
  tags = {}
71
69
  i = 0
72
- while i < content.bytesize do
70
+ while i < content.bytesize
73
71
  tag, size = content[i, 4].unpack('vv')
74
72
  i += 4
75
73
  break unless tag && size
@@ -89,4 +87,4 @@ module Zip
89
87
  ((time.to_f + SEC_TO_UNIX_EPOCH) * WINDOWS_TICK).to_i
90
88
  end
91
89
  end
92
- end
90
+ end
@@ -1,7 +1,7 @@
1
1
  module Zip
2
2
  # Olf Info-ZIP Extra for UNIX uid/gid and file timestampes
3
3
  class ExtraField::OldUnix < ExtraField::Generic
4
- HEADER_ID = "UX"
4
+ HEADER_ID = 'UX'
5
5
  register_map
6
6
 
7
7
  def initialize(binstr = nil)
@@ -9,7 +9,7 @@ module Zip
9
9
  @gid = 0
10
10
  @atime = nil
11
11
  @mtime = nil
12
- binstr and merge(binstr)
12
+ binstr && merge(binstr)
13
13
  end
14
14
 
15
15
  attr_accessor :uid, :gid, :atime, :mtime
@@ -18,8 +18,8 @@ module Zip
18
18
  return if binstr.empty?
19
19
  size, content = initial_parse(binstr)
20
20
  # size: 0 for central directory. 4 for local header
21
- return if (!size || size == 0)
22
- atime, mtime, uid, gid = content.unpack("VVvv")
21
+ return if !size || size == 0
22
+ atime, mtime, uid, gid = content.unpack('VVvv')
23
23
  @uid ||= uid
24
24
  @gid ||= gid
25
25
  @atime ||= atime
@@ -29,17 +29,16 @@ module Zip
29
29
  def ==(other)
30
30
  @uid == other.uid &&
31
31
  @gid == other.gid &&
32
- @atime == other.atime &&
33
- @mtime == other.mtime
32
+ @atime == other.atime &&
33
+ @mtime == other.mtime
34
34
  end
35
35
 
36
36
  def pack_for_local
37
- [@atime, @mtime, @uid, @gid].pack("VVvv")
37
+ [@atime, @mtime, @uid, @gid].pack('VVvv')
38
38
  end
39
39
 
40
40
  def pack_for_c_dir
41
- [@atime, @mtime].pack("VV")
41
+ [@atime, @mtime].pack('VV')
42
42
  end
43
43
  end
44
-
45
- end
44
+ end
@@ -1,7 +1,7 @@
1
1
  module Zip
2
2
  # Info-ZIP Additional timestamp field
3
3
  class ExtraField::UniversalTime < ExtraField::Generic
4
- HEADER_ID = "UT"
4
+ HEADER_ID = 'UT'
5
5
  register_map
6
6
 
7
7
  def initialize(binstr = nil)
@@ -9,7 +9,7 @@ module Zip
9
9
  @mtime = nil
10
10
  @atime = nil
11
11
  @flag = nil
12
- binstr and merge(binstr)
12
+ binstr && merge(binstr)
13
13
  end
14
14
 
15
15
  attr_accessor :atime, :ctime, :mtime, :flag
@@ -17,11 +17,11 @@ module Zip
17
17
  def merge(binstr)
18
18
  return if binstr.empty?
19
19
  size, content = initial_parse(binstr)
20
- size or return
21
- @flag, mtime, atime, ctime = content.unpack("CVVV")
22
- mtime and @mtime ||= ::Zip::DOSTime.at(mtime)
23
- atime and @atime ||= ::Zip::DOSTime.at(atime)
24
- ctime and @ctime ||= ::Zip::DOSTime.at(ctime)
20
+ size || return
21
+ @flag, mtime, atime, ctime = content.unpack('CVVV')
22
+ mtime && @mtime ||= ::Zip::DOSTime.at(mtime)
23
+ atime && @atime ||= ::Zip::DOSTime.at(atime)
24
+ ctime && @ctime ||= ::Zip::DOSTime.at(ctime)
25
25
  end
26
26
 
27
27
  def ==(other)
@@ -31,17 +31,17 @@ module Zip
31
31
  end
32
32
 
33
33
  def pack_for_local
34
- s = [@flag].pack("C")
35
- @flag & 1 != 0 and s << [@mtime.to_i].pack("V")
36
- @flag & 2 != 0 and s << [@atime.to_i].pack("V")
37
- @flag & 4 != 0 and s << [@ctime.to_i].pack("V")
34
+ s = [@flag].pack('C')
35
+ @flag & 1 != 0 && s << [@mtime.to_i].pack('V')
36
+ @flag & 2 != 0 && s << [@atime.to_i].pack('V')
37
+ @flag & 4 != 0 && s << [@ctime.to_i].pack('V')
38
38
  s
39
39
  end
40
40
 
41
41
  def pack_for_c_dir
42
- s = [@flag].pack("C")
43
- @flag & 1 == 1 and s << [@mtime.to_i].pack("V")
42
+ s = [@flag].pack('C')
43
+ @flag & 1 == 1 && s << [@mtime.to_i].pack('V')
44
44
  s
45
45
  end
46
46
  end
47
- end
47
+ end
@@ -1,13 +1,13 @@
1
1
  module Zip
2
2
  # Info-ZIP Extra for UNIX uid/gid
3
3
  class ExtraField::IUnix < ExtraField::Generic
4
- HEADER_ID = "Ux"
4
+ HEADER_ID = 'Ux'
5
5
  register_map
6
6
 
7
7
  def initialize(binstr = nil)
8
8
  @uid = 0
9
9
  @gid = 0
10
- binstr and merge(binstr)
10
+ binstr && merge(binstr)
11
11
  end
12
12
 
13
13
  attr_accessor :uid, :gid
@@ -16,10 +16,10 @@ module Zip
16
16
  return if binstr.empty?
17
17
  size, content = initial_parse(binstr)
18
18
  # size: 0 for central directory. 4 for local header
19
- return if (!size || size == 0)
20
- uid, gid = content.unpack("vv")
21
- @uid ||= uid
22
- @gid ||= gid
19
+ return if !size || size == 0
20
+ uid, gid = content.unpack('vv')
21
+ @uid ||= uid
22
+ @gid ||= gid
23
23
  end
24
24
 
25
25
  def ==(other)
@@ -27,12 +27,11 @@ module Zip
27
27
  end
28
28
 
29
29
  def pack_for_local
30
- [@uid, @gid].pack("vv")
30
+ [@uid, @gid].pack('vv')
31
31
  end
32
32
 
33
33
  def pack_for_c_dir
34
34
  ''
35
35
  end
36
36
  end
37
-
38
- end
37
+ end
@@ -6,21 +6,22 @@ module Zip
6
6
  register_map
7
7
 
8
8
  def initialize(binstr = nil)
9
- @content = nil # unparsed binary; we don't actually know what this contains
10
- # without looking for FFs in the associated file header
11
- # call parse after initializing with a binary string
9
+ # unparsed binary; we don't actually know what this contains
10
+ # without looking for FFs in the associated file header
11
+ # call parse after initializing with a binary string
12
+ @content = nil
12
13
  @original_size = nil
13
14
  @compressed_size = nil
14
15
  @relative_header_offset = nil
15
16
  @disk_start_number = nil
16
- binstr and merge(binstr)
17
+ binstr && merge(binstr)
17
18
  end
18
19
 
19
20
  def ==(other)
20
21
  other.original_size == @original_size &&
21
22
  other.compressed_size == @compressed_size &&
22
- other.relative_header_offset == @relative_header_offset &&
23
- other.disk_start_number == @disk_start_number
23
+ other.relative_header_offset == @relative_header_offset &&
24
+ other.disk_start_number == @disk_start_number
24
25
  end
25
26
 
26
27
  def merge(binstr)
@@ -51,16 +52,16 @@ module Zip
51
52
  def pack_for_local
52
53
  # local header entries must contain original size and compressed size; other fields do not apply
53
54
  return '' unless @original_size && @compressed_size
54
- [@original_size, @compressed_size].pack("Q<Q<")
55
+ [@original_size, @compressed_size].pack('Q<Q<')
55
56
  end
56
57
 
57
58
  def pack_for_c_dir
58
59
  # central directory entries contain only fields that didn't fit in the main entry part
59
60
  packed = ''.force_encoding('BINARY')
60
- packed << [@original_size].pack("Q<") if @original_size
61
- packed << [@compressed_size].pack("Q<") if @compressed_size
62
- packed << [@relative_header_offset].pack("Q<") if @relative_header_offset
63
- packed << [@disk_start_number].pack("V") if @disk_start_number
61
+ packed << [@original_size].pack('Q<') if @original_size
62
+ packed << [@compressed_size].pack('Q<') if @compressed_size
63
+ packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
64
+ packed << [@disk_start_number].pack('V') if @disk_start_number
64
65
  packed
65
66
  end
66
67
  end
@@ -6,7 +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)
9
+ def initialize(_binstr = nil)
10
10
  end
11
11
 
12
12
  def pack_for_local
@@ -43,13 +43,13 @@ module Zip
43
43
  # interface for accessing the filesystem, ie. the File and Dir classes.
44
44
 
45
45
  class File < CentralDirectory
46
-
47
- CREATE = 1
46
+ CREATE = true
48
47
  SPLIT_SIGNATURE = 0x08074b50
49
48
  ZIP64_EOCD_SIGNATURE = 0x06064b50
50
- MAX_SEGMENT_SIZE = 3221225472
51
- MIN_SEGMENT_SIZE = 65536
49
+ MAX_SEGMENT_SIZE = 3_221_225_472
50
+ MIN_SEGMENT_SIZE = 65_536
52
51
  DATA_BUFFER_SIZE = 8192
52
+ IO_METHODS = [:tell, :seek, :read, :close]
53
53
 
54
54
  attr_reader :name
55
55
 
@@ -64,20 +64,22 @@ module Zip
64
64
 
65
65
  # Opens a zip archive. Pass true as the second parameter to create
66
66
  # a new archive if it doesn't exist already.
67
- def initialize(file_name, create = nil, buffer = false, options = {})
67
+ def initialize(file_name, create = false, buffer = false, options = {})
68
68
  super()
69
69
  @name = file_name
70
70
  @comment = ''
71
- @create = create
71
+ @create = create ? true : false # allow any truthy value to mean true
72
72
  case
73
73
  when !buffer && ::File.size?(file_name)
74
- @create = nil
75
- @exist_file_perms = ::File.stat(file_name).mode
74
+ @create = false
75
+ @file_permissions = ::File.stat(file_name).mode
76
76
  ::File.open(name, 'rb') do |f|
77
77
  read_from_stream(f)
78
78
  end
79
- when create
79
+ when @create
80
80
  @entry_set = EntrySet.new
81
+ when ::File.zero?(file_name)
82
+ raise Error, "File #{file_name} has zero size. Did you mean to pass the create flag?"
81
83
  else
82
84
  raise Error, "File #{file_name} not found"
83
85
  end
@@ -92,7 +94,7 @@ module Zip
92
94
  # Same as #new. If a block is passed the ZipFile object is passed
93
95
  # to the block and is automatically closed afterwards just as with
94
96
  # ruby's builtin File.open method.
95
- def open(file_name, create = nil)
97
+ def open(file_name, create = false)
96
98
  zf = ::Zip::File.new(file_name, create)
97
99
  return zf unless block_given?
98
100
  begin
@@ -115,23 +117,24 @@ module Zip
115
117
  # (This can be used to extract data from a
116
118
  # downloaded zip archive without first saving it to disk.)
117
119
  def open_buffer(io, options = {})
118
- unless io.is_a?(IO) || io.is_a?(String) || io.is_a?(Tempfile)
119
- raise "Zip::File.open_buffer expects an argument of class String, IO, or Tempfile. Found: #{io.class}"
120
+ unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
121
+ raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
120
122
  end
121
123
  if io.is_a?(::String)
122
124
  require 'stringio'
123
125
  io = ::StringIO.new(io)
124
- elsif io.is_a?(IO)
126
+ elsif io.respond_to?(:binmode)
125
127
  # https://github.com/rubyzip/rubyzip/issues/119
126
128
  io.binmode
127
129
  end
128
130
  zf = ::Zip::File.new(io, true, true, options)
129
131
  zf.read_from_stream(io)
132
+ return zf unless block_given?
130
133
  yield zf
131
134
  begin
132
135
  zf.write_buffer(io)
133
136
  rescue IOError => e
134
- raise unless e.message == "not opened for writing"
137
+ raise unless e.message == 'not opened for writing'
135
138
  end
136
139
  end
137
140
 
@@ -181,7 +184,7 @@ module Zip
181
184
  def save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
182
185
  ssegment_size = zip_file_size - zip_file.pos
183
186
  ssegment_size = segment_size if ssegment_size > segment_size
184
- szip_file_name = "#{partial_zip_file_name}.#{'%03d'%(szip_file_index)}"
187
+ szip_file_name = "#{partial_zip_file_name}.#{format('%03d', szip_file_index)}"
185
188
  ::File.open(szip_file_name, 'wb') do |szip_file|
186
189
  if szip_file_index == 1
187
190
  ssegment_size = put_split_signature(szip_file, segment_size)
@@ -191,7 +194,7 @@ module Zip
191
194
  segment_bytes_left = ssegment_size - chunk_bytes
192
195
  buffer_size = segment_bytes_left < DATA_BUFFER_SIZE ? segment_bytes_left : DATA_BUFFER_SIZE
193
196
  chunk = zip_file.read(buffer_size)
194
- chunk_bytes += buffer_size
197
+ chunk_bytes += buffer_size
195
198
  szip_file << chunk
196
199
  # Info for track splitting
197
200
  yield segment_count, szip_file_index, chunk_bytes, ssegment_size if block_given?
@@ -208,7 +211,7 @@ module Zip
208
211
  return if zip_file_size <= segment_size
209
212
  segment_count = get_segment_count_for_split(zip_file_size, segment_size)
210
213
  # Checking for correct zip structure
211
- self.open(zip_file_name) {}
214
+ open(zip_file_name) {}
212
215
  partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
213
216
  szip_file_index = 0
214
217
  ::File.open(zip_file_name, 'rb') do |zip_file|
@@ -222,7 +225,6 @@ module Zip
222
225
  end
223
226
  end
224
227
 
225
-
226
228
  # Returns an input stream to the specified entry. If a block is passed
227
229
  # the stream object is passed to the block and the stream is automatically
228
230
  # closed afterwards just as with ruby's builtin File.open method.
@@ -265,7 +267,7 @@ module Zip
265
267
  # Convenience method for adding the contents of a file to the archive
266
268
  def add(entry, src_path, &continue_on_exists_proc)
267
269
  continue_on_exists_proc ||= proc { ::Zip.continue_on_exists_proc }
268
- check_entry_exists(entry, continue_on_exists_proc, "add")
270
+ check_entry_exists(entry, continue_on_exists_proc, 'add')
269
271
  new_entry = entry.kind_of?(::Zip::Entry) ? entry : ::Zip::Entry.new(@name, entry.to_s)
270
272
  new_entry.gather_fileinfo_from_srcpath(src_path)
271
273
  new_entry.dirty = true
@@ -338,7 +340,7 @@ module Zip
338
340
  @entry_set.each do |e|
339
341
  return true if e.dirty
340
342
  end
341
- @comment != @stored_comment || @entry_set != @stored_entries || @create == ::Zip::File::CREATE
343
+ @comment != @stored_comment || @entry_set != @stored_entries || @create
342
344
  end
343
345
 
344
346
  # Searches for entry with the specified name. Returns nil if
@@ -356,9 +358,7 @@ module Zip
356
358
  # if no entry is found.
357
359
  def get_entry(entry)
358
360
  selected_entry = find_entry(entry)
359
- unless selected_entry
360
- raise Errno::ENOENT, entry
361
- end
361
+ raise Errno::ENOENT, entry unless selected_entry
362
362
  selected_entry.restore_ownership = @restore_ownership
363
363
  selected_entry.restore_permissions = @restore_permissions
364
364
  selected_entry.restore_times = @restore_times
@@ -367,9 +367,7 @@ module Zip
367
367
 
368
368
  # Creates a directory
369
369
  def mkdir(entryName, permissionInt = 0755)
370
- if find_entry(entryName)
371
- raise Errno::EEXIST, "File exists - #{entryName}"
372
- end
370
+ raise Errno::EEXIST, "File exists - #{entryName}" if find_entry(entryName)
373
371
  entryName = entryName.dup.to_s
374
372
  entryName << '/' unless entryName.end_with?('/')
375
373
  @entry_set << ::Zip::StreamableDirectory.new(@name, entryName, nil, permissionInt)
@@ -377,57 +375,46 @@ module Zip
377
375
 
378
376
  private
379
377
 
380
- def is_directory(newEntry, srcPath)
378
+ def directory?(newEntry, srcPath)
381
379
  srcPathIsDirectory = ::File.directory?(srcPath)
382
- if newEntry.is_directory && !srcPathIsDirectory
380
+ if newEntry.directory? && !srcPathIsDirectory
383
381
  raise ArgumentError,
384
- "entry name '#{newEntry}' indicates directory entry, but "+
385
- "'#{srcPath}' is not a directory"
386
- elsif !newEntry.is_directory && srcPathIsDirectory
387
- newEntry.name += "/"
382
+ "entry name '#{newEntry}' indicates directory entry, but " \
383
+ "'#{srcPath}' is not a directory"
384
+ elsif !newEntry.directory? && srcPathIsDirectory
385
+ newEntry.name += '/'
388
386
  end
389
- newEntry.is_directory && srcPathIsDirectory
387
+ newEntry.directory? && srcPathIsDirectory
390
388
  end
391
389
 
392
390
  def check_entry_exists(entryName, continue_on_exists_proc, procedureName)
393
391
  continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
394
- if @entry_set.include?(entryName)
395
- if continue_on_exists_proc.call
396
- remove get_entry(entryName)
397
- else
398
- raise ::Zip::EntryExistsError,
399
- procedureName + " failed. Entry #{entryName} already exists"
400
- end
392
+ return unless @entry_set.include?(entryName)
393
+ if continue_on_exists_proc.call
394
+ remove get_entry(entryName)
395
+ else
396
+ raise ::Zip::EntryExistsError,
397
+ procedureName + " failed. Entry #{entryName} already exists"
401
398
  end
402
399
  end
403
400
 
404
401
  def check_file(path)
405
- unless ::File.readable?(path)
406
- raise Errno::ENOENT, path
407
- end
402
+ raise Errno::ENOENT, path unless ::File.readable?(path)
408
403
  end
409
404
 
410
405
  def on_success_replace
411
- tmpfile = get_tempfile
412
- tmp_filename = tmpfile.path
413
- ObjectSpace.undefine_finalizer(tmpfile)
414
- tmpfile.close
415
- if yield tmp_filename
416
- ::File.rename(tmp_filename, self.name)
417
- if defined?(@exist_file_perms)
418
- ::File.chmod(@exist_file_perms, self.name)
406
+ dirname, basename = ::File.split(name)
407
+ ::Dir::Tmpname.create(basename, dirname) do |tmp_filename|
408
+ begin
409
+ if yield tmp_filename
410
+ ::File.rename(tmp_filename, name)
411
+ ::File.chmod(@file_permissions, name) unless @create
412
+ end
413
+ ensure
414
+ ::File.unlink(tmp_filename) if ::File.exist?(tmp_filename)
419
415
  end
420
416
  end
421
- ensure
422
- tmpfile.unlink if tmpfile
423
417
  end
424
-
425
- def get_tempfile
426
- temp_file = Tempfile.new(::File.basename(name), ::File.dirname(name))
427
- temp_file.binmode
428
- temp_file
429
- end
430
-
431
418
  end
432
419
  end
433
420