rubyzip 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7befb1c4855935534788418759d90641e37bd31c53428b5ba04c6c8c4bc4a544
4
- data.tar.gz: 9b5669fc4b3c8a03cc39c73c7ae0e26ece01a2e51a401274f737a43798592b5b
3
+ metadata.gz: cba65b486ec6325e6623957990539a225398a2b9b665b5814a5c06ba70ea1744
4
+ data.tar.gz: 37dc716e5d98048e1b0c72165c16deb6a6bfef02556890f783cdc62ff5021f4e
5
5
  SHA512:
6
- metadata.gz: a537f87d0051073f2a31ced8f732d0b3b5c7376e792d02d3c1a52b597133f0f4be16b6c2c2564624104b179e501b7016ec6fecdde3681709d9730b5fb124dc72
7
- data.tar.gz: 37ed030e2ffbb243bc639e969d050d21836448f746c1d47a49b8f77417b286438bee60dd80a6ba1e333642db218a56d32908ccbce4b3b6873082c42a709c6c77
6
+ metadata.gz: 45de19fa6e2c549c07830243686d622adb937509a942eeb1412a05ea6d1f4a1bde5d60429446ff64f607f3a55400a38c9ccd2d30380825fb4b6e55618702d802
7
+ data.tar.gz: 8d22f9bc464d950e9ede9cfc1da1056ba664ede954b93ae12d0af68e1d859600d8cd63ba5768553f3d810a693d38ce912c0c2d0f3b3d130da973c8bd833fb3bc
data/lib/zip.rb CHANGED
@@ -4,6 +4,7 @@ require 'tempfile'
4
4
  require 'fileutils'
5
5
  require 'stringio'
6
6
  require 'zlib'
7
+ require 'zip/constants'
7
8
  require 'zip/dos_time'
8
9
  require 'zip/ioextras'
9
10
  require 'rbconfig'
@@ -21,6 +22,7 @@ require 'zip/null_compressor'
21
22
  require 'zip/null_input_stream'
22
23
  require 'zip/pass_thru_compressor'
23
24
  require 'zip/pass_thru_decompressor'
25
+ require 'zip/crypto/decrypted_io'
24
26
  require 'zip/crypto/encryption'
25
27
  require 'zip/crypto/null_encryption'
26
28
  require 'zip/crypto/traditional_encryption'
@@ -28,7 +30,6 @@ require 'zip/inflater'
28
30
  require 'zip/deflater'
29
31
  require 'zip/streamable_stream'
30
32
  require 'zip/streamable_directory'
31
- require 'zip/constants'
32
33
  require 'zip/errors'
33
34
 
34
35
  module Zip
@@ -60,4 +60,56 @@ module Zip
60
60
  FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze,
61
61
  FSTYPE_ATHEOS => 'AtheOS'.freeze
62
62
  }.freeze
63
+
64
+ COMPRESSION_METHOD_STORE = 0
65
+ COMPRESSION_METHOD_SHRINK = 1
66
+ COMPRESSION_METHOD_REDUCE_1 = 2
67
+ COMPRESSION_METHOD_REDUCE_2 = 3
68
+ COMPRESSION_METHOD_REDUCE_3 = 4
69
+ COMPRESSION_METHOD_REDUCE_4 = 5
70
+ COMPRESSION_METHOD_IMPLODE = 6
71
+ # RESERVED = 7
72
+ COMPRESSION_METHOD_DEFLATE = 8
73
+ COMPRESSION_METHOD_DEFLATE_64 = 9
74
+ COMPRESSION_METHOD_PKWARE_DCLI = 10
75
+ # RESERVED = 11
76
+ COMPRESSION_METHOD_BZIP2 = 12
77
+ # RESERVED = 13
78
+ COMPRESSION_METHOD_LZMA = 14
79
+ # RESERVED = 15
80
+ COMPRESSION_METHOD_IBM_CMPSC = 16
81
+ # RESERVED = 17
82
+ COMPRESSION_METHOD_IBM_TERSE = 18
83
+ COMPRESSION_METHOD_IBM_LZ77 = 19
84
+ COMPRESSION_METHOD_JPEG = 96
85
+ COMPRESSION_METHOD_WAVPACK = 97
86
+ COMPRESSION_METHOD_PPMD = 98
87
+ COMPRESSION_METHOD_AES = 99
88
+
89
+ COMPRESSION_METHODS = {
90
+ COMPRESSION_METHOD_STORE => 'Store (no compression)',
91
+ COMPRESSION_METHOD_SHRINK => 'Shrink',
92
+ COMPRESSION_METHOD_REDUCE_1 => 'Reduce with compression factor 1',
93
+ COMPRESSION_METHOD_REDUCE_2 => 'Reduce with compression factor 2',
94
+ COMPRESSION_METHOD_REDUCE_3 => 'Reduce with compression factor 3',
95
+ COMPRESSION_METHOD_REDUCE_4 => 'Reduce with compression factor 4',
96
+ COMPRESSION_METHOD_IMPLODE => 'Implode',
97
+ # RESERVED = 7
98
+ COMPRESSION_METHOD_DEFLATE => 'Deflate',
99
+ COMPRESSION_METHOD_DEFLATE_64 => 'Deflate64(tm)',
100
+ COMPRESSION_METHOD_PKWARE_DCLI => 'PKWARE Data Compression Library Imploding (old IBM TERSE)',
101
+ # RESERVED = 11
102
+ COMPRESSION_METHOD_BZIP2 => 'BZIP2',
103
+ # RESERVED = 13
104
+ COMPRESSION_METHOD_LZMA => 'LZMA',
105
+ # RESERVED = 15
106
+ COMPRESSION_METHOD_IBM_CMPSC => 'IBM z/OS CMPSC Compression',
107
+ # RESERVED = 17
108
+ COMPRESSION_METHOD_IBM_TERSE => 'IBM TERSE (new)',
109
+ COMPRESSION_METHOD_IBM_LZ77 => 'IBM LZ77 z Architecture (PFS)',
110
+ COMPRESSION_METHOD_JPEG => 'JPEG variant',
111
+ COMPRESSION_METHOD_WAVPACK => 'WavPack compressed data',
112
+ COMPRESSION_METHOD_PPMD => 'PPMd version I, Rev 1',
113
+ COMPRESSION_METHOD_AES => 'AES encryption',
114
+ }.freeze
63
115
  end
@@ -0,0 +1,39 @@
1
+ module Zip
2
+ class DecryptedIo #:nodoc:all
3
+ CHUNK_SIZE = 32_768
4
+
5
+ def initialize(io, decrypter)
6
+ @io = io
7
+ @decrypter = decrypter
8
+ end
9
+
10
+ def read(length = nil, outbuf = '')
11
+ return ((length.nil? || length.zero?) ? "" : nil) if eof
12
+
13
+ while length.nil? || (buffer.bytesize < length)
14
+ break if input_finished?
15
+ buffer << produce_input
16
+ end
17
+
18
+ outbuf.replace(buffer.slice!(0...(length || output_buffer.bytesize)))
19
+ end
20
+
21
+ private
22
+
23
+ def eof
24
+ buffer.empty? && input_finished?
25
+ end
26
+
27
+ def buffer
28
+ @buffer ||= ''.dup
29
+ end
30
+
31
+ def input_finished?
32
+ @io.eof
33
+ end
34
+
35
+ def produce_input
36
+ @decrypter.decrypt(@io.read(CHUNK_SIZE))
37
+ end
38
+ end
39
+ end
@@ -1,9 +1,27 @@
1
1
  module Zip
2
2
  class Decompressor #:nodoc:all
3
3
  CHUNK_SIZE = 32_768
4
- def initialize(input_stream)
4
+
5
+ def self.decompressor_classes
6
+ @decompressor_classes ||= {}
7
+ end
8
+
9
+ def self.register(compression_method, decompressor_class)
10
+ decompressor_classes[compression_method] = decompressor_class
11
+ end
12
+
13
+ def self.find_by_compression_method(compression_method)
14
+ decompressor_classes[compression_method]
15
+ end
16
+
17
+ attr_reader :input_stream
18
+ attr_reader :decompressed_size
19
+
20
+ def initialize(input_stream, decompressed_size = nil)
5
21
  super()
22
+
6
23
  @input_stream = input_stream
24
+ @decompressed_size = decompressed_size
7
25
  end
8
26
  end
9
27
  end
@@ -72,6 +72,14 @@ module Zip
72
72
  @extra = ::Zip::ExtraField.new(@extra.to_s) unless @extra.is_a?(::Zip::ExtraField)
73
73
  end
74
74
 
75
+ def encrypted?
76
+ gp_flags & 1 == 1
77
+ end
78
+
79
+ def incomplete?
80
+ gp_flags & 8 == 8
81
+ end
82
+
75
83
  def time
76
84
  if @extra['UniversalTime']
77
85
  @extra['UniversalTime'].mtime
@@ -7,6 +7,7 @@ module Zip
7
7
  class EntrySizeError < Error; end
8
8
  class InternalError < Error; end
9
9
  class GPFBit3Error < Error; end
10
+ class DecompressionError < Error; end
10
11
 
11
12
  # Backwards compatibility with v1 (delete in v2)
12
13
  ZipError = Error
@@ -49,7 +49,7 @@ module Zip
49
49
  MAX_SEGMENT_SIZE = 3_221_225_472
50
50
  MIN_SEGMENT_SIZE = 65_536
51
51
  DATA_BUFFER_SIZE = 8192
52
- IO_METHODS = [:tell, :seek, :read, :close]
52
+ IO_METHODS = [:tell, :seek, :read, :eof, :close]
53
53
 
54
54
  DEFAULT_OPTIONS = {
55
55
  restore_ownership: false,
@@ -1,64 +1,50 @@
1
1
  module Zip
2
2
  class Inflater < Decompressor #:nodoc:all
3
- def initialize(input_stream, decrypter = NullDecrypter.new)
4
- super(input_stream)
5
- @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
6
- @output_buffer = ''.dup
7
- @has_returned_empty_string = false
8
- @decrypter = decrypter
9
- end
3
+ def initialize(*args)
4
+ super
10
5
 
11
- def sysread(number_of_bytes = nil, buf = '')
12
- readEverything = number_of_bytes.nil?
13
- while readEverything || @output_buffer.bytesize < number_of_bytes
14
- break if internal_input_finished?
15
- @output_buffer << internal_produce_input(buf)
16
- end
17
- return value_when_finished if @output_buffer.bytesize == 0 && input_finished?
18
- end_index = number_of_bytes.nil? ? @output_buffer.bytesize : number_of_bytes
19
- @output_buffer.slice!(0...end_index)
6
+ @buffer = ''.dup
7
+ @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
20
8
  end
21
9
 
22
- def produce_input
23
- if @output_buffer.empty?
24
- internal_produce_input
25
- else
26
- @output_buffer.slice!(0...(@output_buffer.length))
10
+ def read(length = nil, outbuf = '')
11
+ return ((length.nil? || length.zero?) ? "" : nil) if eof
12
+
13
+ while length.nil? || (@buffer.bytesize < length)
14
+ break if input_finished?
15
+ @buffer << produce_input
27
16
  end
17
+
18
+ outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
28
19
  end
29
20
 
30
- # to be used with produce_input, not read (as read may still have more data cached)
31
- # is data cached anywhere other than @outputBuffer? the comment above may be wrong
32
- def input_finished?
33
- @output_buffer.empty? && internal_input_finished?
21
+ def eof
22
+ @buffer.empty? && input_finished?
34
23
  end
35
24
 
36
- alias :eof input_finished?
37
- alias :eof? input_finished?
25
+ alias_method :eof?, :eof
38
26
 
39
27
  private
40
28
 
41
- def internal_produce_input(buf = '')
29
+ def produce_input
42
30
  retried = 0
43
31
  begin
44
- @zlib_inflater.inflate(@decrypter.decrypt(@input_stream.read(Decompressor::CHUNK_SIZE, buf)))
32
+ @zlib_inflater.inflate(input_stream.read(Decompressor::CHUNK_SIZE))
45
33
  rescue Zlib::BufError
46
34
  raise if retried >= 5 # how many times should we retry?
47
35
  retried += 1
48
36
  retry
49
37
  end
38
+ rescue Zlib::Error
39
+ raise(::Zip::DecompressionError, 'zlib error while inflating')
50
40
  end
51
41
 
52
- def internal_input_finished?
42
+ def input_finished?
53
43
  @zlib_inflater.finished?
54
44
  end
55
-
56
- def value_when_finished # mimic behaviour of ruby File object.
57
- return if @has_returned_empty_string
58
- @has_returned_empty_string = true
59
- ''
60
- end
61
45
  end
46
+
47
+ ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_DEFLATE, ::Zip::Inflater)
62
48
  end
63
49
 
64
50
  # Copyright (C) 2002, 2003 Thomas Sondergaard
@@ -39,6 +39,8 @@ module Zip
39
39
  # class.
40
40
 
41
41
  class InputStream
42
+ CHUNK_SIZE = 32_768
43
+
42
44
  include ::Zip::IOExtras::AbstractInputStream
43
45
 
44
46
  # Opens the indicated zip file. An exception is thrown
@@ -78,16 +80,10 @@ module Zip
78
80
  end
79
81
 
80
82
  # Modeled after IO.sysread
81
- def sysread(number_of_bytes = nil, buf = nil)
82
- @decompressor.sysread(number_of_bytes, buf)
83
- end
84
-
85
- def eof
86
- @output_buffer.empty? && @decompressor.eof
83
+ def sysread(length = nil, outbuf = '')
84
+ @decompressor.read(length, outbuf)
87
85
  end
88
86
 
89
- alias :eof? eof
90
-
91
87
  class << self
92
88
  # Same as #initialize but if a block is passed the opened
93
89
  # stream is passed to the block and closed when the block
@@ -124,46 +120,54 @@ module Zip
124
120
 
125
121
  def open_entry
126
122
  @current_entry = ::Zip::Entry.read_local_entry(@archive_io)
127
- if @current_entry && @current_entry.gp_flags & 1 == 1 && @decrypter.is_a?(NullEncrypter)
123
+ if @current_entry && @current_entry.encrypted? && @decrypter.is_a?(NullEncrypter)
128
124
  raise Error, 'password required to decode zip file'
129
125
  end
130
- if @current_entry && @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 \
126
+ if @current_entry && @current_entry.incomplete? && @current_entry.crc == 0 \
131
127
  && @current_entry.compressed_size == 0 \
132
128
  && @current_entry.size == 0 && !@complete_entry
133
129
  raise GPFBit3Error,
134
130
  'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
135
131
  'Please use ::Zip::File instead of ::Zip::InputStream'
136
132
  end
133
+ @decrypted_io = get_decrypted_io
137
134
  @decompressor = get_decompressor
138
135
  flush
139
136
  @current_entry
140
137
  end
141
138
 
139
+ def get_decrypted_io
140
+ header = @archive_io.read(@decrypter.header_bytesize)
141
+ @decrypter.reset!(header)
142
+
143
+ ::Zip::DecryptedIo.new(@archive_io, @decrypter)
144
+ end
145
+
142
146
  def get_decompressor
143
- if @current_entry.nil?
144
- ::Zip::NullDecompressor
145
- elsif @current_entry.compression_method == ::Zip::Entry::STORED
146
- if @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
147
- ::Zip::PassThruDecompressor.new(@archive_io, @complete_entry.size)
147
+ return ::Zip::NullDecompressor if @current_entry.nil?
148
+
149
+ decompressed_size =
150
+ if @current_entry.incomplete? && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
151
+ @complete_entry.size
148
152
  else
149
- ::Zip::PassThruDecompressor.new(@archive_io, @current_entry.size)
153
+ @current_entry.size
150
154
  end
151
- elsif @current_entry.compression_method == ::Zip::Entry::DEFLATED
152
- header = @archive_io.read(@decrypter.header_bytesize)
153
- @decrypter.reset!(header)
154
- ::Zip::Inflater.new(@archive_io, @decrypter)
155
- else
155
+
156
+ decompressor_class = ::Zip::Decompressor.find_by_compression_method(@current_entry.compression_method)
157
+ if decompressor_class.nil?
156
158
  raise ::Zip::CompressionMethodError,
157
159
  "Unsupported compression method #{@current_entry.compression_method}"
158
160
  end
161
+
162
+ decompressor_class.new(@decrypted_io, decompressed_size)
159
163
  end
160
164
 
161
165
  def produce_input
162
- @decompressor.produce_input
166
+ @decompressor.read(CHUNK_SIZE)
163
167
  end
164
168
 
165
169
  def input_finished?
166
- @decompressor.input_finished?
170
+ @decompressor.eof
167
171
  end
168
172
  end
169
173
  end
@@ -106,6 +106,12 @@ module Zip
106
106
  end
107
107
 
108
108
  alias_method :each, :each_line
109
+
110
+ def eof
111
+ @output_buffer.empty? && input_finished?
112
+ end
113
+
114
+ alias_method :eof?, :eof
109
115
  end
110
116
  end
111
117
  end
@@ -2,18 +2,10 @@ module Zip
2
2
  module NullDecompressor #:nodoc:all
3
3
  module_function
4
4
 
5
- def sysread(_numberOfBytes = nil, _buf = nil)
5
+ def read(_length = nil, _outbuf = nil)
6
6
  nil
7
7
  end
8
8
 
9
- def produce_input
10
- nil
11
- end
12
-
13
- def input_finished?
14
- true
15
- end
16
-
17
9
  def eof
18
10
  true
19
11
  end
@@ -1,38 +1,29 @@
1
1
  module Zip
2
2
  class PassThruDecompressor < Decompressor #:nodoc:all
3
- def initialize(input_stream, chars_to_read)
4
- super(input_stream)
5
- @chars_to_read = chars_to_read
3
+ def initialize(*args)
4
+ super
6
5
  @read_so_far = 0
7
- @has_returned_empty_string = false
8
6
  end
9
7
 
10
- def sysread(number_of_bytes = nil, buf = '')
11
- if input_finished?
12
- has_returned_empty_string_val = @has_returned_empty_string
13
- @has_returned_empty_string = true
14
- return '' unless has_returned_empty_string_val
15
- return
16
- end
8
+ def read(length = nil, outbuf = '')
9
+ return ((length.nil? || length.zero?) ? "" : nil) if eof
17
10
 
18
- if number_of_bytes.nil? || @read_so_far + number_of_bytes > @chars_to_read
19
- number_of_bytes = @chars_to_read - @read_so_far
11
+ if length.nil? || (@read_so_far + length) > decompressed_size
12
+ length = decompressed_size - @read_so_far
20
13
  end
21
- @read_so_far += number_of_bytes
22
- @input_stream.read(number_of_bytes, buf)
23
- end
24
14
 
25
- def produce_input
26
- sysread(::Zip::Decompressor::CHUNK_SIZE)
15
+ @read_so_far += length
16
+ input_stream.read(length, outbuf)
27
17
  end
28
18
 
29
- def input_finished?
30
- @read_so_far >= @chars_to_read
19
+ def eof
20
+ @read_so_far >= decompressed_size
31
21
  end
32
22
 
33
- alias eof input_finished?
34
- alias eof? input_finished?
23
+ alias_method :eof?, :eof
35
24
  end
25
+
26
+ ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
36
27
  end
37
28
 
38
29
  # Copyright (C) 2002, 2003 Thomas Sondergaard
@@ -1,3 +1,3 @@
1
1
  module Zip
2
- VERSION = '2.1.0'
2
+ VERSION = '2.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyzip
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Simonov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-25 00:00:00.000000000 Z
11
+ date: 2020-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -94,6 +94,7 @@ files:
94
94
  - lib/zip/central_directory.rb
95
95
  - lib/zip/compressor.rb
96
96
  - lib/zip/constants.rb
97
+ - lib/zip/crypto/decrypted_io.rb
97
98
  - lib/zip/crypto/encryption.rb
98
99
  - lib/zip/crypto/null_encryption.rb
99
100
  - lib/zip/crypto/traditional_encryption.rb
@@ -139,9 +140,9 @@ licenses:
139
140
  - BSD 2-Clause
140
141
  metadata:
141
142
  bug_tracker_uri: https://github.com/rubyzip/rubyzip/issues
142
- changelog_uri: https://github.com/rubyzip/rubyzip/blob/v2.1.0/Changelog.md
143
- documentation_uri: https://www.rubydoc.info/gems/rubyzip/2.1.0
144
- source_code_uri: https://github.com/rubyzip/rubyzip/tree/v2.1.0
143
+ changelog_uri: https://github.com/rubyzip/rubyzip/blob/v2.2.0/Changelog.md
144
+ documentation_uri: https://www.rubydoc.info/gems/rubyzip/2.2.0
145
+ source_code_uri: https://github.com/rubyzip/rubyzip/tree/v2.2.0
145
146
  wiki_uri: https://github.com/rubyzip/rubyzip/wiki
146
147
  post_install_message:
147
148
  rdoc_options: []