rubyzip 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []