rubyzip 1.1.7 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +137 -54
  3. data/Rakefile +6 -4
  4. data/lib/zip/central_directory.rb +17 -13
  5. data/lib/zip/compressor.rb +1 -2
  6. data/lib/zip/constants.rb +57 -5
  7. data/lib/zip/crypto/decrypted_io.rb +40 -0
  8. data/lib/zip/crypto/null_encryption.rb +4 -6
  9. data/lib/zip/crypto/traditional_encryption.rb +14 -14
  10. data/lib/zip/decompressor.rb +22 -4
  11. data/lib/zip/deflater.rb +8 -6
  12. data/lib/zip/dos_time.rb +17 -13
  13. data/lib/zip/entry.rb +171 -148
  14. data/lib/zip/entry_set.rb +16 -14
  15. data/lib/zip/errors.rb +3 -0
  16. data/lib/zip/extra_field/generic.rb +14 -13
  17. data/lib/zip/extra_field/ntfs.rb +18 -16
  18. data/lib/zip/extra_field/old_unix.rb +12 -11
  19. data/lib/zip/extra_field/universal_time.rb +46 -16
  20. data/lib/zip/extra_field/unix.rb +10 -9
  21. data/lib/zip/extra_field/zip64.rb +15 -12
  22. data/lib/zip/extra_field/zip64_placeholder.rb +1 -2
  23. data/lib/zip/extra_field.rb +18 -16
  24. data/lib/zip/file.rb +147 -115
  25. data/lib/zip/filesystem.rb +289 -272
  26. data/lib/zip/inflater.rb +24 -36
  27. data/lib/zip/input_stream.rb +44 -28
  28. data/lib/zip/ioextras/abstract_input_stream.rb +24 -17
  29. data/lib/zip/ioextras/abstract_output_stream.rb +4 -6
  30. data/lib/zip/ioextras.rb +2 -4
  31. data/lib/zip/null_compressor.rb +2 -2
  32. data/lib/zip/null_decompressor.rb +3 -11
  33. data/lib/zip/null_input_stream.rb +0 -0
  34. data/lib/zip/output_stream.rb +25 -17
  35. data/lib/zip/pass_thru_compressor.rb +6 -6
  36. data/lib/zip/pass_thru_decompressor.rb +14 -24
  37. data/lib/zip/streamable_directory.rb +3 -3
  38. data/lib/zip/streamable_stream.rb +7 -11
  39. data/lib/zip/version.rb +1 -1
  40. data/lib/zip.rb +15 -6
  41. data/samples/example.rb +29 -39
  42. data/samples/example_filesystem.rb +16 -18
  43. data/samples/example_recursive.rb +31 -25
  44. data/samples/gtk_ruby_zip.rb +84 -0
  45. data/samples/qtzip.rb +23 -32
  46. data/samples/write_simple.rb +10 -13
  47. data/samples/zipfind.rb +33 -40
  48. metadata +50 -141
  49. data/samples/gtkRubyzip.rb +0 -86
  50. data/test/basic_zip_file_test.rb +0 -64
  51. data/test/central_directory_entry_test.rb +0 -73
  52. data/test/central_directory_test.rb +0 -104
  53. data/test/crypto/null_encryption_test.rb +0 -53
  54. data/test/crypto/traditional_encryption_test.rb +0 -80
  55. data/test/data/WarnInvalidDate.zip +0 -0
  56. data/test/data/file1.txt +0 -46
  57. data/test/data/file1.txt.deflatedData +0 -0
  58. data/test/data/file2.txt +0 -1504
  59. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  60. data/test/data/globTest/foo.txt +0 -0
  61. data/test/data/globTest/food.txt +0 -0
  62. data/test/data/globTest.zip +0 -0
  63. data/test/data/mimetype +0 -1
  64. data/test/data/notzippedruby.rb +0 -7
  65. data/test/data/ntfs.zip +0 -0
  66. data/test/data/rubycode.zip +0 -0
  67. data/test/data/rubycode2.zip +0 -0
  68. data/test/data/testDirectory.bin +0 -0
  69. data/test/data/zip64-sample.zip +0 -0
  70. data/test/data/zipWithDirs.zip +0 -0
  71. data/test/data/zipWithEncryption.zip +0 -0
  72. data/test/deflater_test.rb +0 -67
  73. data/test/encryption_test.rb +0 -42
  74. data/test/entry_set_test.rb +0 -138
  75. data/test/entry_test.rb +0 -165
  76. data/test/errors_test.rb +0 -36
  77. data/test/extra_field_test.rb +0 -78
  78. data/test/file_extract_directory_test.rb +0 -56
  79. data/test/file_extract_test.rb +0 -90
  80. data/test/file_split_test.rb +0 -60
  81. data/test/file_test.rb +0 -559
  82. data/test/filesystem/dir_iterator_test.rb +0 -62
  83. data/test/filesystem/directory_test.rb +0 -131
  84. data/test/filesystem/file_mutating_test.rb +0 -100
  85. data/test/filesystem/file_nonmutating_test.rb +0 -514
  86. data/test/filesystem/file_stat_test.rb +0 -66
  87. data/test/gentestfiles.rb +0 -134
  88. data/test/inflater_test.rb +0 -14
  89. data/test/input_stream_test.rb +0 -170
  90. data/test/ioextras/abstract_input_stream_test.rb +0 -103
  91. data/test/ioextras/abstract_output_stream_test.rb +0 -106
  92. data/test/ioextras/fake_io_test.rb +0 -18
  93. data/test/local_entry_test.rb +0 -156
  94. data/test/output_stream_test.rb +0 -129
  95. data/test/pass_thru_compressor_test.rb +0 -31
  96. data/test/pass_thru_decompressor_test.rb +0 -15
  97. data/test/settings_test.rb +0 -92
  98. data/test/test_helper.rb +0 -228
  99. data/test/unicode_file_names_and_comments_test.rb +0 -52
  100. data/test/zip64_full_test.rb +0 -53
  101. data/test/zip64_support_test.rb +0 -15
data/lib/zip/entry_set.rb CHANGED
@@ -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
 
@@ -18,28 +18,24 @@ 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
- def each(&block)
36
+ def each
41
37
  @entry_set = sorted_entries.dup.each do |_, value|
42
- block.call(value)
38
+ yield(value)
43
39
  end
44
40
  end
45
41
 
@@ -49,11 +45,12 @@ 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)
56
52
  return false unless other.kind_of?(EntrySet)
53
+
57
54
  @entry_set.values == other.entry_set.values
58
55
  end
59
56
 
@@ -61,22 +58,27 @@ module Zip
61
58
  @entry_set[to_key(entry.parent_as_string)]
62
59
  end
63
60
 
64
- def glob(pattern, flags = ::File::FNM_PATHNAME|::File::FNM_DOTMATCH)
61
+ def glob(pattern, flags = ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH | ::File::FNM_EXTGLOB)
65
62
  entries.map do |entry|
66
63
  next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
64
+
67
65
  yield(entry) if block_given?
68
66
  entry
69
67
  end.compact
70
68
  end
71
69
 
72
70
  protected
71
+
73
72
  def sorted_entries
74
73
  ::Zip.sort_entries ? Hash[@entry_set.sort] : @entry_set
75
74
  end
76
75
 
77
76
  private
77
+
78
78
  def to_key(entry)
79
- entry.to_s.chomp('/')
79
+ k = entry.to_s.chomp('/')
80
+ k.downcase! if ::Zip.case_insensitive_match
81
+ k
80
82
  end
81
83
  end
82
84
  end
data/lib/zip/errors.rb CHANGED
@@ -4,7 +4,10 @@ module Zip
4
4
  class DestinationFileExistsError < Error; end
5
5
  class CompressionMethodError < Error; end
6
6
  class EntryNameError < Error; end
7
+ class EntrySizeError < Error; end
7
8
  class InternalError < Error; end
9
+ class GPFBit3Error < Error; end
10
+ class DecompressionError < Error; end
8
11
 
9
12
  # Backwards compatibility with v1 (delete in v2)
10
13
  ZipError = Error
@@ -1,43 +1,44 @@
1
1
  module Zip
2
2
  class ExtraField::Generic
3
3
  def self.register_map
4
- if self.const_defined?(:HEADER_ID)
5
- ::Zip::ExtraField::ID_MAP[self.const_get(:HEADER_ID)] = self
6
- end
4
+ return unless const_defined?(:HEADER_ID)
5
+
6
+ ::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
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
14
14
  def initial_parse(binstr)
15
- if !binstr
16
- # If nil, start with empty.
17
- return false
18
- elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
19
- $stderr.puts "Warning: weired extra feild header ID. skip parsing"
15
+ return false unless binstr
16
+
17
+ if binstr[0, 2] != self.class.const_get(:HEADER_ID)
18
+ warn 'WARNING: weird extra field header ID. Skip parsing it.'
20
19
  return false
21
20
  end
22
- [binstr[2, 2].unpack("v")[0], binstr[4..-1]]
21
+
22
+ [binstr[2, 2].unpack1('v'), binstr[4..-1]]
23
23
  end
24
24
 
25
25
  def ==(other)
26
26
  return false if self.class != other.class
27
+
27
28
  each do |k, v|
28
- v != other[k] and return false
29
+ return false if v != other[k]
29
30
  end
30
31
  true
31
32
  end
32
33
 
33
34
  def to_local_bin
34
35
  s = pack_for_local
35
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack("v") << s
36
+ self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
36
37
  end
37
38
 
38
39
  def to_c_dir_bin
39
40
  s = pack_for_c_dir
40
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack("v") << s
41
+ self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
41
42
  end
42
43
  end
43
44
  end
@@ -5,33 +5,34 @@ 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
19
19
 
20
20
  def merge(binstr)
21
21
  return if binstr.empty?
22
+
22
23
  size, content = initial_parse(binstr)
23
- (size && content) or return
24
+ (size && content) || return
24
25
 
25
26
  content = content[4..-1]
26
27
  tags = parse_tags(content)
27
28
 
28
29
  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
30
+ return unless tag1
31
+
32
+ ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
33
+ ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
34
+ ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
35
+ ntfs_ctime && @ctime ||= from_ntfs_time(ntfs_ctime)
35
36
  end
36
37
 
37
38
  def ==(other)
@@ -48,16 +49,14 @@ module Zip
48
49
  # But 7-zip for Windows only stores at central dir
49
50
  def pack_for_c_dir
50
51
  # reserved 0 and tag 1
51
- s = [0, 1].pack("Vv")
52
+ s = [0, 1].pack('Vv')
52
53
 
53
54
  tag1 = ''.force_encoding(Encoding::BINARY)
54
55
  if @mtime
55
56
  tag1 << [to_ntfs_time(@mtime)].pack('Q<')
56
57
  if @atime
57
58
  tag1 << [to_ntfs_time(@atime)].pack('Q<')
58
- if @ctime
59
- tag1 << [to_ntfs_time(@ctime)].pack('Q<')
60
- end
59
+ tag1 << [to_ntfs_time(@ctime)].pack('Q<') if @ctime
61
60
  end
62
61
  end
63
62
  s << [tag1.bytesize].pack('v') << tag1
@@ -65,14 +64,17 @@ module Zip
65
64
  end
66
65
 
67
66
  private
67
+
68
68
  def parse_tags(content)
69
69
  return {} if content.nil?
70
+
70
71
  tags = {}
71
72
  i = 0
72
- while i < content.bytesize do
73
+ while i < content.bytesize
73
74
  tag, size = content[i, 4].unpack('vv')
74
75
  i += 4
75
76
  break unless tag && size
77
+
76
78
  value = content[i, size]
77
79
  i += size
78
80
  tags[tag] = value
@@ -89,4 +91,4 @@ module Zip
89
91
  ((time.to_f + SEC_TO_UNIX_EPOCH) * WINDOWS_TICK).to_i
90
92
  end
91
93
  end
92
- end
94
+ 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,37 +9,38 @@ 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
16
16
 
17
17
  def merge(binstr)
18
18
  return if binstr.empty?
19
+
19
20
  size, content = initial_parse(binstr)
20
21
  # size: 0 for central directory. 4 for local header
21
- return if (!size || size == 0)
22
- atime, mtime, uid, gid = content.unpack("VVvv")
22
+ return if !size || size == 0
23
+
24
+ atime, mtime, uid, gid = content.unpack('VVvv')
23
25
  @uid ||= uid
24
26
  @gid ||= gid
25
27
  @atime ||= atime
26
- @mtime ||= mtime
28
+ @mtime ||= mtime # rubocop:disable Naming/MemoizedInstanceVariableName
27
29
  end
28
30
 
29
31
  def ==(other)
30
32
  @uid == other.uid &&
31
33
  @gid == other.gid &&
32
- @atime == other.atime &&
33
- @mtime == other.mtime
34
+ @atime == other.atime &&
35
+ @mtime == other.mtime
34
36
  end
35
37
 
36
38
  def pack_for_local
37
- [@atime, @mtime, @uid, @gid].pack("VVvv")
39
+ [@atime, @mtime, @uid, @gid].pack('VVvv')
38
40
  end
39
41
 
40
42
  def pack_for_c_dir
41
- [@atime, @mtime].pack("VV")
43
+ [@atime, @mtime].pack('VV')
42
44
  end
43
45
  end
44
-
45
- end
46
+ end
@@ -1,27 +1,57 @@
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
+ ATIME_MASK = 0b010
8
+ CTIME_MASK = 0b100
9
+ MTIME_MASK = 0b001
10
+
7
11
  def initialize(binstr = nil)
8
12
  @ctime = nil
9
13
  @mtime = nil
10
14
  @atime = nil
11
- @flag = nil
12
- binstr and merge(binstr)
15
+ @flag = 0
16
+
17
+ merge(binstr) unless binstr.nil?
18
+ end
19
+
20
+ attr_reader :atime, :ctime, :mtime, :flag
21
+
22
+ def atime=(time)
23
+ @flag = time.nil? ? @flag & ~ATIME_MASK : @flag | ATIME_MASK
24
+ @atime = time
25
+ end
26
+
27
+ def ctime=(time)
28
+ @flag = time.nil? ? @flag & ~CTIME_MASK : @flag | CTIME_MASK
29
+ @ctime = time
13
30
  end
14
31
 
15
- attr_accessor :atime, :ctime, :mtime, :flag
32
+ def mtime=(time)
33
+ @flag = time.nil? ? @flag & ~MTIME_MASK : @flag | MTIME_MASK
34
+ @mtime = time
35
+ end
16
36
 
17
37
  def merge(binstr)
18
38
  return if binstr.empty?
39
+
19
40
  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)
41
+ return if !size || size <= 0
42
+
43
+ @flag, *times = content.unpack('Cl<l<l<')
44
+
45
+ # Parse the timestamps, in order, based on which flags are set.
46
+ return if times[0].nil?
47
+
48
+ @mtime ||= ::Zip::DOSTime.at(times.shift) unless @flag & MTIME_MASK == 0
49
+ return if times[0].nil?
50
+
51
+ @atime ||= ::Zip::DOSTime.at(times.shift) unless @flag & ATIME_MASK == 0
52
+ return if times[0].nil?
53
+
54
+ @ctime ||= ::Zip::DOSTime.at(times.shift) unless @flag & CTIME_MASK == 0
25
55
  end
26
56
 
27
57
  def ==(other)
@@ -31,17 +61,17 @@ module Zip
31
61
  end
32
62
 
33
63
  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")
64
+ s = [@flag].pack('C')
65
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
66
+ s << [@atime.to_i].pack('l<') unless @flag & ATIME_MASK == 0
67
+ s << [@ctime.to_i].pack('l<') unless @flag & CTIME_MASK == 0
38
68
  s
39
69
  end
40
70
 
41
71
  def pack_for_c_dir
42
- s = [@flag].pack("C")
43
- @flag & 1 == 1 and s << [@mtime.to_i].pack("V")
72
+ s = [@flag].pack('C')
73
+ s << [@mtime.to_i].pack('l<') unless @flag & MTIME_MASK == 0
44
74
  s
45
75
  end
46
76
  end
47
- end
77
+ end
@@ -1,25 +1,27 @@
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
14
14
 
15
15
  def merge(binstr)
16
16
  return if binstr.empty?
17
+
17
18
  size, content = initial_parse(binstr)
18
19
  # 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
20
+ return if !size || size == 0
21
+
22
+ uid, gid = content.unpack('vv')
23
+ @uid ||= uid
24
+ @gid ||= gid # rubocop:disable Naming/MemoizedInstanceVariableName
23
25
  end
24
26
 
25
27
  def ==(other)
@@ -27,12 +29,11 @@ module Zip
27
29
  end
28
30
 
29
31
  def pack_for_local
30
- [@uid, @gid].pack("vv")
32
+ [@uid, @gid].pack('vv')
31
33
  end
32
34
 
33
35
  def pack_for_c_dir
34
36
  ''
35
37
  end
36
38
  end
37
-
38
- end
39
+ end
@@ -6,25 +6,27 @@ 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)
27
28
  return if binstr.empty?
29
+
28
30
  _, @content = initial_parse(binstr)
29
31
  end
30
32
 
@@ -44,23 +46,24 @@ module Zip
44
46
  end
45
47
 
46
48
  def extract(size, format)
47
- @content.slice!(0, size).unpack(format)[0]
49
+ @content.slice!(0, size).unpack1(format)
48
50
  end
49
51
  private :extract
50
52
 
51
53
  def pack_for_local
52
54
  # local header entries must contain original size and compressed size; other fields do not apply
53
55
  return '' unless @original_size && @compressed_size
54
- [@original_size, @compressed_size].pack("Q<Q<")
56
+
57
+ [@original_size, @compressed_size].pack('Q<Q<')
55
58
  end
56
59
 
57
60
  def pack_for_c_dir
58
61
  # central directory entries contain only fields that didn't fit in the main entry part
59
62
  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
63
+ packed << [@original_size].pack('Q<') if @original_size
64
+ packed << [@compressed_size].pack('Q<') if @compressed_size
65
+ packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
66
+ packed << [@disk_start_number].pack('V') if @disk_start_number
64
67
  packed
65
68
  end
66
69
  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
@@ -3,30 +3,30 @@ 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
- def extra_field_type_exist(binstr, id, len, i)
9
+ def extra_field_type_exist(binstr, id, len, index)
10
10
  field_name = ID_MAP[id].name
11
- if self.member?(field_name)
12
- self[field_name].merge(binstr[i, len + 4])
11
+ if member?(field_name)
12
+ self[field_name].merge(binstr[index, len + 4])
13
13
  else
14
- field_obj = ID_MAP[id].new(binstr[i, len + 4])
14
+ field_obj = ID_MAP[id].new(binstr[index, len + 4])
15
15
  self[field_name] = field_obj
16
16
  end
17
17
  end
18
18
 
19
- def extra_field_type_unknown(binstr, len, i)
19
+ def extra_field_type_unknown(binstr, len, index)
20
20
  create_unknown_item unless self['Unknown']
21
- if !len || len + 4 > binstr[i..-1].bytesize
22
- self['Unknown'] << binstr[i..-1]
21
+ if !len || len + 4 > binstr[index..-1].bytesize
22
+ self['Unknown'] << binstr[index..-1]
23
23
  return
24
24
  end
25
- self['Unknown'] << binstr[i, len + 4]
25
+ self['Unknown'] << binstr[index, len + 4]
26
26
  end
27
27
 
28
28
  def create_unknown_item
29
- s = ''
29
+ s = +''
30
30
  class << s
31
31
  alias_method :to_c_dir_bin, :to_s
32
32
  alias_method :to_local_bin, :to_s
@@ -36,10 +36,11 @@ module Zip
36
36
 
37
37
  def merge(binstr)
38
38
  return if binstr.empty?
39
+
39
40
  i = 0
40
41
  while i < binstr.bytesize
41
42
  id = binstr[i, 2]
42
- len = binstr[i + 2, 2].to_s.unpack('v').first
43
+ len = binstr[i + 2, 2].to_s.unpack1('v')
43
44
  if id && ID_MAP.member?(id)
44
45
  extra_field_type_exist(binstr, id, len, i)
45
46
  elsif id
@@ -51,9 +52,10 @@ module Zip
51
52
  end
52
53
 
53
54
  def create(name)
54
- unless field_class = ID_MAP.values.find { |k| k.name == name }
55
+ unless (field_class = ID_MAP.values.find { |k| k.name == name })
55
56
  raise Error, "Unknown extra field '#{name}'"
56
57
  end
58
+
57
59
  self[name] = field_class.new
58
60
  end
59
61
 
@@ -61,7 +63,7 @@ module Zip
61
63
  # does not prevent known fields from being read back in
62
64
  def ordered_values
63
65
  result = []
64
- self.each { |k,v| k == 'Unknown' ? result.push(v) : result.unshift(v) }
66
+ each { |k, v| k == 'Unknown' ? result.push(v) : result.unshift(v) }
65
67
  result
66
68
  end
67
69
 
@@ -69,7 +71,7 @@ module Zip
69
71
  ordered_values.map! { |v| v.to_local_bin.force_encoding('BINARY') }.join
70
72
  end
71
73
 
72
- alias :to_s :to_local_bin
74
+ alias to_s to_local_bin
73
75
 
74
76
  def to_c_dir_bin
75
77
  ordered_values.map! { |v| v.to_c_dir_bin.force_encoding('BINARY') }.join
@@ -83,8 +85,8 @@ module Zip
83
85
  to_local_bin.bytesize
84
86
  end
85
87
 
86
- alias :length :local_size
87
- alias :size :local_size
88
+ alias length local_size
89
+ alias size local_size
88
90
  end
89
91
  end
90
92