rubyzip 1.1.7 → 1.2.4
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.
- checksums.yaml +5 -5
- data/README.md +87 -45
- data/Rakefile +3 -4
- data/lib/zip.rb +11 -5
- data/lib/zip/central_directory.rb +8 -8
- data/lib/zip/compressor.rb +1 -2
- data/lib/zip/constants.rb +5 -5
- data/lib/zip/crypto/null_encryption.rb +4 -6
- data/lib/zip/crypto/traditional_encryption.rb +5 -5
- data/lib/zip/decompressor.rb +3 -3
- data/lib/zip/deflater.rb +8 -6
- data/lib/zip/dos_time.rb +5 -6
- data/lib/zip/entry.rb +120 -128
- data/lib/zip/entry_set.rb +14 -14
- data/lib/zip/errors.rb +1 -0
- data/lib/zip/extra_field.rb +8 -8
- data/lib/zip/extra_field/generic.rb +8 -8
- data/lib/zip/extra_field/ntfs.rb +14 -16
- data/lib/zip/extra_field/old_unix.rb +9 -10
- data/lib/zip/extra_field/universal_time.rb +14 -14
- data/lib/zip/extra_field/unix.rb +8 -9
- data/lib/zip/extra_field/zip64.rb +12 -11
- data/lib/zip/extra_field/zip64_placeholder.rb +1 -2
- data/lib/zip/file.rb +81 -81
- data/lib/zip/filesystem.rb +144 -143
- data/lib/zip/inflater.rb +5 -5
- data/lib/zip/input_stream.rb +22 -13
- data/lib/zip/ioextras.rb +1 -3
- data/lib/zip/ioextras/abstract_input_stream.rb +6 -10
- data/lib/zip/ioextras/abstract_output_stream.rb +3 -5
- data/lib/zip/null_compressor.rb +2 -2
- data/lib/zip/null_decompressor.rb +3 -3
- data/lib/zip/null_input_stream.rb +0 -0
- data/lib/zip/output_stream.rb +13 -14
- data/lib/zip/pass_thru_compressor.rb +4 -4
- data/lib/zip/pass_thru_decompressor.rb +3 -4
- data/lib/zip/streamable_directory.rb +2 -2
- data/lib/zip/streamable_stream.rb +3 -3
- data/lib/zip/version.rb +1 -1
- data/samples/example.rb +29 -39
- data/samples/example_filesystem.rb +16 -18
- data/samples/example_recursive.rb +31 -25
- data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +23 -25
- data/samples/qtzip.rb +18 -27
- data/samples/write_simple.rb +12 -13
- data/samples/zipfind.rb +26 -34
- data/test/basic_zip_file_test.rb +11 -15
- data/test/case_sensitivity_test.rb +69 -0
- data/test/central_directory_entry_test.rb +32 -36
- data/test/central_directory_test.rb +46 -50
- data/test/crypto/null_encryption_test.rb +8 -4
- data/test/crypto/traditional_encryption_test.rb +5 -5
- data/test/data/gpbit3stored.zip +0 -0
- data/test/data/notzippedruby.rb +1 -1
- data/test/data/oddExtraField.zip +0 -0
- data/test/data/path_traversal/Makefile +10 -0
- data/test/data/path_traversal/jwilk/README.md +5 -0
- data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
- data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
- data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
- data/test/data/path_traversal/jwilk/relative0.zip +0 -0
- data/test/data/path_traversal/jwilk/relative2.zip +0 -0
- data/test/data/path_traversal/jwilk/symlink.zip +0 -0
- data/test/data/path_traversal/relative1.zip +0 -0
- data/test/data/path_traversal/tilde.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/README.md +3 -0
- data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
- data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/test.xls +0 -0
- data/test/deflater_test.rb +10 -12
- data/test/encryption_test.rb +2 -2
- data/test/entry_set_test.rb +50 -25
- data/test/entry_test.rb +76 -87
- data/test/errors_test.rb +1 -2
- data/test/extra_field_test.rb +19 -21
- data/test/file_extract_directory_test.rb +12 -14
- data/test/file_extract_test.rb +33 -40
- data/test/file_permissions_test.rb +65 -0
- data/test/file_split_test.rb +24 -27
- data/test/file_test.rb +266 -179
- data/test/filesystem/dir_iterator_test.rb +13 -17
- data/test/filesystem/directory_test.rb +101 -93
- data/test/filesystem/file_mutating_test.rb +52 -65
- data/test/filesystem/file_nonmutating_test.rb +223 -229
- data/test/filesystem/file_stat_test.rb +17 -19
- data/test/gentestfiles.rb +54 -62
- data/test/inflater_test.rb +1 -1
- data/test/input_stream_test.rb +52 -40
- data/test/ioextras/abstract_input_stream_test.rb +22 -23
- data/test/ioextras/abstract_output_stream_test.rb +33 -33
- data/test/ioextras/fake_io_test.rb +1 -1
- data/test/local_entry_test.rb +36 -38
- data/test/output_stream_test.rb +20 -21
- data/test/pass_thru_compressor_test.rb +5 -6
- data/test/pass_thru_decompressor_test.rb +0 -1
- data/test/path_traversal_test.rb +141 -0
- data/test/samples/example_recursive_test.rb +37 -0
- data/test/settings_test.rb +18 -15
- data/test/test_helper.rb +52 -46
- data/test/unicode_file_names_and_comments_test.rb +17 -7
- data/test/zip64_full_test.rb +10 -12
- data/test/zip64_support_test.rb +0 -1
- metadata +94 -65
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
|
24
|
+
alias push <<
|
25
25
|
|
26
26
|
def size
|
27
27
|
@entry_set.size
|
28
28
|
end
|
29
29
|
|
30
|
-
alias
|
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
|
36
|
+
def each
|
41
37
|
@entry_set = sorted_entries.dup.each do |_, value|
|
42
|
-
|
38
|
+
yield(value)
|
43
39
|
end
|
44
40
|
end
|
45
41
|
|
@@ -49,7 +45,7 @@ module Zip
|
|
49
45
|
|
50
46
|
# deep clone
|
51
47
|
def dup
|
52
|
-
EntrySet.new(@entry_set.map
|
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
|
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
|
data/lib/zip/errors.rb
CHANGED
data/lib/zip/extra_field.rb
CHANGED
@@ -3,12 +3,12 @@ module Zip
|
|
3
3
|
ID_MAP = {}
|
4
4
|
|
5
5
|
def initialize(binstr = nil)
|
6
|
-
binstr
|
6
|
+
merge(binstr) if binstr
|
7
7
|
end
|
8
8
|
|
9
9
|
def extra_field_type_exist(binstr, id, len, i)
|
10
10
|
field_name = ID_MAP[id].name
|
11
|
-
if
|
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])
|
@@ -26,7 +26,7 @@ module Zip
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def create_unknown_item
|
29
|
-
s = ''
|
29
|
+
s = ''.dup
|
30
30
|
class << s
|
31
31
|
alias_method :to_c_dir_bin, :to_s
|
32
32
|
alias_method :to_local_bin, :to_s
|
@@ -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
|
-
|
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
|
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
|
87
|
-
alias
|
86
|
+
alias length local_size
|
87
|
+
alias size local_size
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Zip
|
2
2
|
class ExtraField::Generic
|
3
3
|
def self.register_map
|
4
|
-
if
|
5
|
-
::Zip::ExtraField::ID_MAP[
|
4
|
+
if const_defined?(:HEADER_ID)
|
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 ||=
|
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
|
19
|
+
$stderr.puts 'Warning: weired extra feild header ID. skip parsing'
|
20
20
|
return false
|
21
21
|
end
|
22
|
-
[binstr[2, 2].unpack(
|
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]
|
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(
|
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(
|
40
|
+
self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
data/lib/zip/extra_field/ntfs.rb
CHANGED
@@ -5,14 +5,14 @@ module Zip
|
|
5
5
|
HEADER_ID = [0x000A].pack('v')
|
6
6
|
register_map
|
7
7
|
|
8
|
-
WINDOWS_TICK =
|
9
|
-
SEC_TO_UNIX_EPOCH =
|
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
|
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)
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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(
|
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
|
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 =
|
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
|
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
|
22
|
-
atime, mtime, uid, gid = content.unpack(
|
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
|
-
|
33
|
-
|
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(
|
37
|
+
[@atime, @mtime, @uid, @gid].pack('VVvv')
|
38
38
|
end
|
39
39
|
|
40
40
|
def pack_for_c_dir
|
41
|
-
[@atime, @mtime].pack(
|
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 =
|
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
|
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
|
21
|
-
@flag, mtime, atime, ctime = content.unpack(
|
22
|
-
mtime
|
23
|
-
atime
|
24
|
-
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(
|
35
|
-
@flag & 1 != 0
|
36
|
-
@flag & 2 != 0
|
37
|
-
@flag & 4 != 0
|
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(
|
43
|
-
@flag & 1 == 1
|
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
|
data/lib/zip/extra_field/unix.rb
CHANGED
@@ -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 =
|
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
|
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
|
20
|
-
uid, gid = content.unpack(
|
21
|
-
@uid
|
22
|
-
@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(
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
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
|
-
|
23
|
-
|
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(
|
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(
|
61
|
-
packed << [@compressed_size].pack(
|
62
|
-
packed << [@relative_header_offset].pack(
|
63
|
-
packed << [@disk_start_number].pack(
|
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
|