rubyzip 2.4.rc1 → 3.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +368 -0
  3. data/README.md +112 -37
  4. data/Rakefile +11 -7
  5. data/lib/zip/central_directory.rb +164 -118
  6. data/lib/zip/compressor.rb +3 -1
  7. data/lib/zip/constants.rb +25 -21
  8. data/lib/zip/crypto/decrypted_io.rb +3 -1
  9. data/lib/zip/crypto/encryption.rb +4 -2
  10. data/lib/zip/crypto/null_encryption.rb +5 -3
  11. data/lib/zip/crypto/traditional_encryption.rb +5 -3
  12. data/lib/zip/decompressor.rb +4 -3
  13. data/lib/zip/deflater.rb +10 -8
  14. data/lib/zip/dirtyable.rb +32 -0
  15. data/lib/zip/dos_time.rb +32 -3
  16. data/lib/zip/entry.rb +263 -199
  17. data/lib/zip/entry_set.rb +9 -7
  18. data/lib/zip/errors.rb +115 -16
  19. data/lib/zip/extra_field/generic.rb +3 -10
  20. data/lib/zip/extra_field/ntfs.rb +4 -2
  21. data/lib/zip/extra_field/old_unix.rb +3 -1
  22. data/lib/zip/extra_field/universal_time.rb +3 -1
  23. data/lib/zip/extra_field/unix.rb +5 -3
  24. data/lib/zip/extra_field/unknown.rb +33 -0
  25. data/lib/zip/extra_field/zip64.rb +12 -5
  26. data/lib/zip/extra_field.rb +15 -21
  27. data/lib/zip/file.rb +143 -264
  28. data/lib/zip/file_split.rb +97 -0
  29. data/lib/zip/filesystem/dir.rb +86 -0
  30. data/lib/zip/filesystem/directory_iterator.rb +48 -0
  31. data/lib/zip/filesystem/file.rb +262 -0
  32. data/lib/zip/filesystem/file_stat.rb +110 -0
  33. data/lib/zip/filesystem/zip_file_name_mapper.rb +81 -0
  34. data/lib/zip/filesystem.rb +26 -595
  35. data/lib/zip/inflater.rb +7 -5
  36. data/lib/zip/input_stream.rb +44 -39
  37. data/lib/zip/ioextras/abstract_input_stream.rb +14 -9
  38. data/lib/zip/ioextras/abstract_output_stream.rb +5 -3
  39. data/lib/zip/ioextras.rb +6 -6
  40. data/lib/zip/null_compressor.rb +3 -1
  41. data/lib/zip/null_decompressor.rb +3 -1
  42. data/lib/zip/null_input_stream.rb +3 -1
  43. data/lib/zip/output_stream.rb +47 -48
  44. data/lib/zip/pass_thru_compressor.rb +3 -1
  45. data/lib/zip/pass_thru_decompressor.rb +4 -2
  46. data/lib/zip/streamable_directory.rb +3 -1
  47. data/lib/zip/streamable_stream.rb +3 -0
  48. data/lib/zip/version.rb +3 -1
  49. data/lib/zip.rb +15 -16
  50. data/rubyzip.gemspec +38 -0
  51. data/samples/example.rb +8 -3
  52. data/samples/example_filesystem.rb +2 -1
  53. data/samples/example_recursive.rb +3 -1
  54. data/samples/gtk_ruby_zip.rb +4 -2
  55. data/samples/qtzip.rb +6 -5
  56. data/samples/write_simple.rb +1 -0
  57. data/samples/zipfind.rb +1 -0
  58. metadata +81 -46
  59. data/TODO +0 -15
  60. data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
4
  # InputStream is the basic class for reading zip entries in a
3
5
  # zip file. It is possible to create a InputStream object directly,
@@ -49,30 +51,30 @@ module Zip
49
51
  #
50
52
  # @param context [String||IO||StringIO] file path or IO/StringIO object
51
53
  # @param offset [Integer] offset in the IO/StringIO
52
- def initialize(context, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
54
+ def initialize(context, offset: 0, decrypter: nil)
53
55
  super()
54
-
55
- if !dep_offset.zero? || !dep_decrypter.nil?
56
- Zip.warn_about_v3_api('Zip::InputStream.new')
57
- end
58
-
59
- offset = dep_offset if offset.zero?
60
- @archive_io = get_io(context, offset)
61
- @decompressor = ::Zip::NullDecompressor
62
- @decrypter = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
56
+ @archive_io = get_io(context, offset)
57
+ @decompressor = ::Zip::NullDecompressor
58
+ @decrypter = decrypter || ::Zip::NullDecrypter.new
63
59
  @current_entry = nil
60
+ @complete_entry = nil
64
61
  end
65
62
 
66
63
  def close
67
64
  @archive_io.close
68
65
  end
69
66
 
70
- # Returns a Entry object. It is necessary to call this
71
- # method on a newly created InputStream before reading from
72
- # the first entry in the archive. Returns nil when there are
73
- # no more entries.
67
+ # Returns an Entry object and positions the stream at the beginning of
68
+ # the entry data. It is necessary to call this method on a newly created
69
+ # InputStream before reading from the first entry in the archive.
70
+ # Returns nil when there are no more entries.
74
71
  def get_next_entry
75
- @archive_io.seek(@current_entry.next_header_offset, IO::SEEK_SET) if @current_entry
72
+ unless @current_entry.nil?
73
+ raise StreamingError, @current_entry if @current_entry.incomplete?
74
+
75
+ @archive_io.seek(@current_entry.next_header_offset, IO::SEEK_SET)
76
+ end
77
+
76
78
  open_entry
77
79
  end
78
80
 
@@ -91,18 +93,19 @@ module Zip
91
93
  @decompressor.read(length, outbuf)
92
94
  end
93
95
 
96
+ # Returns the size of the current entry, or `nil` if there isn't one.
97
+ def size
98
+ return if @current_entry.nil?
99
+
100
+ @current_entry.size
101
+ end
102
+
94
103
  class << self
95
104
  # Same as #initialize but if a block is passed the opened
96
105
  # stream is passed to the block and closed when the block
97
106
  # returns.
98
- def open(filename_or_io, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
99
- if !dep_offset.zero? || !dep_decrypter.nil?
100
- Zip.warn_about_v3_api('Zip::InputStream.new')
101
- end
102
-
103
- offset = dep_offset if offset.zero?
104
-
105
- zio = new(filename_or_io, offset: offset, decrypter: decrypter || dep_decrypter)
107
+ def open(filename_or_io, offset: 0, decrypter: nil)
108
+ zio = new(filename_or_io, offset: offset, decrypter: decrypter)
106
109
  return zio unless block_given?
107
110
 
108
111
  begin
@@ -112,10 +115,9 @@ module Zip
112
115
  end
113
116
  end
114
117
 
115
- def open_buffer(filename_or_io, offset = 0)
116
- Zip.warn_about_v3_api('Zip::InputStream.open_buffer')
117
-
118
- ::Zip::InputStream.open(filename_or_io, offset)
118
+ def open_buffer(filename_or_io, offset: 0)
119
+ warn 'open_buffer is deprecated!!! Use open instead!'
120
+ ::Zip::InputStream.open(filename_or_io, offset: offset)
119
121
  end
120
122
  end
121
123
 
@@ -135,17 +137,18 @@ module Zip
135
137
 
136
138
  def open_entry
137
139
  @current_entry = ::Zip::Entry.read_local_entry(@archive_io)
138
- if @current_entry && @current_entry.encrypted? && @decrypter.kind_of?(NullEncrypter)
139
- raise Error, 'password required to decode zip file'
140
+ return if @current_entry.nil?
141
+
142
+ if @current_entry.encrypted? && @decrypter.kind_of?(NullDecrypter)
143
+ raise Error,
144
+ 'A password is required to decode this zip file'
140
145
  end
141
146
 
142
- if @current_entry && @current_entry.incomplete? && @current_entry.crc == 0 \
143
- && @current_entry.compressed_size == 0 \
144
- && @current_entry.size == 0 && !@complete_entry
145
- raise GPFBit3Error,
146
- 'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
147
- 'Please use ::Zip::File instead of ::Zip::InputStream'
147
+ if @current_entry.incomplete? && @current_entry.compressed_size == 0 \
148
+ && !@complete_entry
149
+ raise StreamingError, @current_entry
148
150
  end
151
+
149
152
  @decrypted_io = get_decrypted_io
150
153
  @decompressor = get_decompressor
151
154
  flush
@@ -163,16 +166,18 @@ module Zip
163
166
  return ::Zip::NullDecompressor if @current_entry.nil?
164
167
 
165
168
  decompressed_size =
166
- if @current_entry.incomplete? && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
169
+ if @current_entry.incomplete? && @current_entry.crc == 0 \
170
+ && @current_entry.size == 0 && @complete_entry
167
171
  @complete_entry.size
168
172
  else
169
173
  @current_entry.size
170
174
  end
171
175
 
172
- decompressor_class = ::Zip::Decompressor.find_by_compression_method(@current_entry.compression_method)
176
+ decompressor_class = ::Zip::Decompressor.find_by_compression_method(
177
+ @current_entry.compression_method
178
+ )
173
179
  if decompressor_class.nil?
174
- raise ::Zip::CompressionMethodError,
175
- "Unsupported compression method #{@current_entry.compression_method}"
180
+ raise ::Zip::CompressionMethodError, @current_entry.compression_method
176
181
  end
177
182
 
178
183
  decompressor_class.new(@decrypted_io, decompressed_size)
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- module IOExtras
4
+ module IOExtras # :nodoc:
3
5
  # Implements many of the convenience methods of IO
4
6
  # such as gets, getc, readline and readlines
5
7
  # depends on: input_finished?, produce_input and read
6
- module AbstractInputStream
8
+ module AbstractInputStream # :nodoc:
7
9
  include Enumerable
8
10
  include FakeIO
9
11
 
@@ -11,22 +13,22 @@ module Zip
11
13
  super
12
14
  @lineno = 0
13
15
  @pos = 0
14
- @output_buffer = ''.b
16
+ @output_buffer = +''
15
17
  end
16
18
 
17
19
  attr_accessor :lineno
18
20
  attr_reader :pos
19
21
 
20
- def read(number_of_bytes = nil, buf = ''.b)
22
+ def read(number_of_bytes = nil, buf = +'')
21
23
  tbuf = if @output_buffer.bytesize > 0
22
- if number_of_bytes <= @output_buffer.bytesize
24
+ if number_of_bytes && number_of_bytes <= @output_buffer.bytesize
23
25
  @output_buffer.slice!(0, number_of_bytes)
24
26
  else
25
27
  number_of_bytes -= @output_buffer.bytesize if number_of_bytes
26
28
  rbuf = sysread(number_of_bytes, buf)
27
29
  out = @output_buffer
28
30
  out << rbuf if rbuf
29
- @output_buffer = ''.b
31
+ @output_buffer = ''
30
32
  out
31
33
  end
32
34
  else
@@ -34,7 +36,7 @@ module Zip
34
36
  end
35
37
 
36
38
  if tbuf.nil? || tbuf.empty?
37
- return nil if number_of_bytes
39
+ return nil if number_of_bytes&.positive?
38
40
 
39
41
  return ''
40
42
  end
@@ -82,7 +84,10 @@ module Zip
82
84
  @output_buffer << produce_input
83
85
  over_limit = (number_of_bytes && @output_buffer.bytesize >= number_of_bytes)
84
86
  end
85
- sep_index = [match_index + a_sep_string.bytesize, number_of_bytes || @output_buffer.bytesize].min
87
+ sep_index = [
88
+ match_index + a_sep_string.bytesize,
89
+ number_of_bytes || @output_buffer.bytesize
90
+ ].min
86
91
  @pos += sep_index
87
92
  @output_buffer.slice!(0...sep_index)
88
93
  end
@@ -93,7 +98,7 @@ module Zip
93
98
 
94
99
  def flush
95
100
  ret_val = @output_buffer
96
- @output_buffer = ''.b
101
+ @output_buffer = +''
97
102
  ret_val
98
103
  end
99
104
 
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- module IOExtras
4
+ module IOExtras # :nodoc:
3
5
  # Implements many of the output convenience methods of IO.
4
6
  # relies on <<
5
- module AbstractOutputStream
7
+ module AbstractOutputStream # :nodoc:
6
8
  include FakeIO
7
9
 
8
10
  def write(data)
@@ -11,7 +13,7 @@ module Zip
11
13
  end
12
14
 
13
15
  def print(*params)
14
- self << params.join($OUTPUT_FIELD_SEPARATOR) << $OUTPUT_RECORD_SEPARATOR.to_s
16
+ self << params.join << $OUTPUT_RECORD_SEPARATOR.to_s
15
17
  end
16
18
 
17
19
  def printf(a_format_string, *params)
data/lib/zip/ioextras.rb CHANGED
@@ -1,26 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- module IOExtras #:nodoc:
4
+ module IOExtras # :nodoc:
3
5
  CHUNK_SIZE = 131_072
4
6
 
5
- RANGE_ALL = 0..-1
6
-
7
7
  class << self
8
8
  def copy_stream(ostream, istream)
9
- ostream.write(istream.read(CHUNK_SIZE, ''.b)) until istream.eof?
9
+ ostream.write(istream.read(CHUNK_SIZE, +'')) until istream.eof?
10
10
  end
11
11
 
12
12
  def copy_stream_n(ostream, istream, nbytes)
13
13
  toread = nbytes
14
14
  while toread > 0 && !istream.eof?
15
15
  tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
16
- ostream.write(istream.read(tr, ''.b))
16
+ ostream.write(istream.read(tr, +''))
17
17
  toread -= tr
18
18
  end
19
19
  end
20
20
  end
21
21
 
22
22
  # Implements kind_of? in order to pretend to be an IO object
23
- module FakeIO
23
+ module FakeIO # :nodoc:
24
24
  def kind_of?(object)
25
25
  object == IO || super
26
26
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- class NullCompressor < Compressor #:nodoc:all
4
+ class NullCompressor < Compressor # :nodoc:all
3
5
  include Singleton
4
6
 
5
7
  def <<(_data)
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- module NullDecompressor #:nodoc:all
4
+ module NullDecompressor # :nodoc:all
3
5
  module_function
4
6
 
5
7
  def read(_length = nil, _outbuf = nil)
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- module NullInputStream #:nodoc:all
4
+ module NullInputStream # :nodoc:all
3
5
  include ::Zip::NullDecompressor
4
6
  include ::Zip::IOExtras::AbstractInputStream
5
7
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
1
5
  module Zip
2
6
  # ZipOutputStream is the basic class for writing zip files. It is
3
7
  # possible to create a ZipOutputStream object directly, passing
@@ -18,55 +22,48 @@ module Zip
18
22
  # class.
19
23
 
20
24
  class OutputStream
25
+ extend Forwardable
21
26
  include ::Zip::IOExtras::AbstractOutputStream
22
27
 
23
- attr_accessor :comment
28
+ def_delegators :@cdir, :comment, :comment=
24
29
 
25
30
  # Opens the indicated zip file. If a file with that name already
26
31
  # exists it will be overwritten.
27
- def initialize(file_name, dep_stream = false, dep_encrypter = nil, stream: false, encrypter: nil)
32
+ def initialize(file_name, stream: false, encrypter: nil)
28
33
  super()
29
-
30
- Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
31
-
32
34
  @file_name = file_name
33
- @output_stream = if stream || dep_stream
34
- iostream = @file_name.dup
35
+ @output_stream = if stream
36
+ iostream = Zip::RUNNING_ON_WINDOWS ? @file_name : @file_name.dup
35
37
  iostream.reopen(@file_name)
36
38
  iostream.rewind
37
39
  iostream
38
40
  else
39
41
  ::File.new(@file_name, 'wb')
40
42
  end
41
- @entry_set = ::Zip::EntrySet.new
43
+ @cdir = ::Zip::CentralDirectory.new
42
44
  @compressor = ::Zip::NullCompressor.instance
43
- @encrypter = encrypter || dep_encrypter || ::Zip::NullEncrypter.new
45
+ @encrypter = encrypter || ::Zip::NullEncrypter.new
44
46
  @closed = false
45
47
  @current_entry = nil
46
- @comment = nil
47
48
  end
48
49
 
49
50
  # Same as #initialize but if a block is passed the opened
50
51
  # stream is passed to the block and closed when the block
51
52
  # returns.
52
53
  class << self
53
- def open(file_name, dep_encrypter = nil, encrypter: nil)
54
+ def open(file_name, encrypter: nil)
54
55
  return new(file_name) unless block_given?
55
56
 
56
- Zip.warn_about_v3_api('Zip::OutputStream.open') unless dep_encrypter.nil?
57
-
58
- zos = new(file_name, stream: false, encrypter: (encrypter || dep_encrypter))
57
+ zos = new(file_name, stream: false, encrypter: encrypter)
59
58
  yield zos
60
59
  ensure
61
60
  zos.close if zos
62
61
  end
63
62
 
64
63
  # Same as #open but writes to a filestream instead
65
- def write_buffer(io = ::StringIO.new, dep_encrypter = nil, encrypter: nil)
66
- Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil?
67
-
64
+ def write_buffer(io = ::StringIO.new, encrypter: nil)
68
65
  io.binmode if io.respond_to?(:binmode)
69
- zos = new(io, stream: true, encrypter: (encrypter || dep_encrypter))
66
+ zos = new(io, stream: true, encrypter: encrypter)
70
67
  yield zos
71
68
  zos.close_buffer
72
69
  end
@@ -78,7 +75,7 @@ module Zip
78
75
 
79
76
  finalize_current_entry
80
77
  update_local_headers
81
- write_central_directory
78
+ @cdir.write_to_stream(@output_stream)
82
79
  @output_stream.close
83
80
  @closed = true
84
81
  end
@@ -89,27 +86,31 @@ module Zip
89
86
 
90
87
  finalize_current_entry
91
88
  update_local_headers
92
- write_central_directory
89
+ @cdir.write_to_stream(@output_stream)
93
90
  @closed = true
91
+ @output_stream.flush
94
92
  @output_stream
95
93
  end
96
94
 
97
95
  # Closes the current entry and opens a new for writing.
98
96
  # +entry+ can be a ZipEntry object or a string.
99
- def put_next_entry(entry_name, comment = nil, extra = nil, compression_method = Entry::DEFLATED, level = Zip.default_compression)
97
+ def put_next_entry(
98
+ entry_name, comment = '', extra = ExtraField.new,
99
+ compression_method = Entry::DEFLATED, level = Zip.default_compression
100
+ )
100
101
  raise Error, 'zip stream is closed' if @closed
101
102
 
102
- new_entry = if entry_name.kind_of?(Entry)
103
- entry_name
104
- else
105
- Entry.new(@file_name, entry_name.to_s)
106
- end
107
- new_entry.comment = comment unless comment.nil?
108
- unless extra.nil?
109
- new_entry.extra = extra.kind_of?(ExtraField) ? extra : ExtraField.new(extra.to_s)
110
- end
111
- new_entry.compression_method = compression_method unless compression_method.nil?
112
- init_next_entry(new_entry, level)
103
+ new_entry =
104
+ if entry_name.kind_of?(Entry) || entry_name.kind_of?(StreamableStream)
105
+ entry_name
106
+ else
107
+ Entry.new(
108
+ @file_name, entry_name.to_s, comment: comment, extra: extra,
109
+ compression_method: compression_method, compression_level: level
110
+ )
111
+ end
112
+
113
+ init_next_entry(new_entry)
113
114
  @current_entry = new_entry
114
115
  end
115
116
 
@@ -119,7 +120,7 @@ module Zip
119
120
  raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
120
121
 
121
122
  finalize_current_entry
122
- @entry_set << entry
123
+ @cdir << entry
123
124
  src_pos = entry.local_header_offset
124
125
  entry.write_local_entry(@output_stream)
125
126
  @compressor = NullCompressor.instance
@@ -143,47 +144,45 @@ module Zip
143
144
  @current_entry.calculate_local_header_size
144
145
  @current_entry.size = @compressor.size
145
146
  @current_entry.crc = @compressor.crc
146
- @output_stream << @encrypter.data_descriptor(@current_entry.crc, @current_entry.compressed_size, @current_entry.size)
147
+ @output_stream << @encrypter.data_descriptor(
148
+ @current_entry.crc,
149
+ @current_entry.compressed_size,
150
+ @current_entry.size
151
+ )
147
152
  @current_entry.gp_flags |= @encrypter.gp_flags
148
153
  @current_entry = nil
149
154
  @compressor = ::Zip::NullCompressor.instance
150
155
  end
151
156
 
152
- def init_next_entry(entry, level = Zip.default_compression)
157
+ def init_next_entry(entry)
153
158
  finalize_current_entry
154
- @entry_set << entry
159
+ @cdir << entry
155
160
  entry.write_local_entry(@output_stream)
156
161
  @encrypter.reset!
157
162
  @output_stream << @encrypter.header(entry.mtime)
158
- @compressor = get_compressor(entry, level)
163
+ @compressor = get_compressor(entry)
159
164
  end
160
165
 
161
- def get_compressor(entry, level)
166
+ def get_compressor(entry)
162
167
  case entry.compression_method
163
168
  when Entry::DEFLATED
164
- ::Zip::Deflater.new(@output_stream, level, @encrypter)
169
+ ::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
165
170
  when Entry::STORED
166
171
  ::Zip::PassThruCompressor.new(@output_stream)
167
172
  else
168
- raise ::Zip::CompressionMethodError,
169
- "Invalid compression method: '#{entry.compression_method}'"
173
+ raise ::Zip::CompressionMethodError, entry.compression_method
170
174
  end
171
175
  end
172
176
 
173
177
  def update_local_headers
174
178
  pos = @output_stream.pos
175
- @entry_set.each do |entry|
179
+ @cdir.each do |entry|
176
180
  @output_stream.pos = entry.local_header_offset
177
- entry.write_local_entry(@output_stream, true)
181
+ entry.write_local_entry(@output_stream, rewrite: true)
178
182
  end
179
183
  @output_stream.pos = pos
180
184
  end
181
185
 
182
- def write_central_directory
183
- cdir = CentralDirectory.new(@entry_set, @comment)
184
- cdir.write_to_stream(@output_stream)
185
- end
186
-
187
186
  protected
188
187
 
189
188
  def finish
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- class PassThruCompressor < Compressor #:nodoc:all
4
+ class PassThruCompressor < Compressor # :nodoc:all
3
5
  def initialize(output_stream)
4
6
  super()
5
7
  @output_stream = output_stream
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- class PassThruDecompressor < Decompressor #:nodoc:all
4
+ class PassThruDecompressor < Decompressor # :nodoc:all
3
5
  def initialize(*args)
4
6
  super
5
7
  @read_so_far = 0
6
8
  end
7
9
 
8
- def read(length = nil, outbuf = ''.b)
10
+ def read(length = nil, outbuf = +'')
9
11
  return (length.nil? || length.zero? ? '' : nil) if eof
10
12
 
11
13
  if length.nil? || (@read_so_far + length) > decompressed_size
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- class StreamableDirectory < Entry
4
+ class StreamableDirectory < Entry # :nodoc:
3
5
  def initialize(zipfile, entry, src_path = nil, permission = nil)
4
6
  super(zipfile, entry)
5
7
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
4
  class StreamableStream < DelegateClass(Entry) # :nodoc:all
3
5
  def initialize(entry)
@@ -42,6 +44,7 @@ module Zip
42
44
  end
43
45
 
44
46
  def clean_up
47
+ super
45
48
  @temp_file.unlink
46
49
  end
47
50
  end
data/lib/zip/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zip
2
- VERSION = '2.4.rc1'
4
+ VERSION = '3.0.0.alpha'
3
5
  end
data/lib/zip.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'English'
2
4
  require 'delegate'
3
5
  require 'singleton'
@@ -33,22 +35,12 @@ require 'zip/streamable_stream'
33
35
  require 'zip/streamable_directory'
34
36
  require 'zip/errors'
35
37
 
38
+ # Rubyzip is a ruby module for reading and writing zip files.
39
+ #
40
+ # The main entry points are File, InputStream and OutputStream. For a
41
+ # file/directory interface in the style of the standard ruby ::File and
42
+ # ::Dir APIs then `require 'zip/filesystem'` and see FileSystem.
36
43
  module Zip
37
- V3_API_WARNING_MSG = <<~END_MSG
38
- You have called '%s' which is changing or deprecated
39
- in version 3.0.0. Please see
40
- https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x
41
- for more information.
42
- END_MSG
43
-
44
- def self.warn_about_v3_api(method)
45
- warn V3_API_WARNING_MSG % method if ENV['RUBYZIP_V3_API_WARN']
46
- end
47
-
48
- if RUBY_VERSION < '3.0'
49
- warn 'RubyZip 3.0 will require Ruby 3.0 or later.' if ENV['RUBYZIP_V3_API_WARN']
50
- end
51
-
52
44
  extend self
53
45
  attr_accessor :unicode_names,
54
46
  :on_exists_proc,
@@ -61,6 +53,12 @@ module Zip
61
53
  :force_entry_names_encoding,
62
54
  :validate_entry_sizes
63
55
 
56
+ DEFAULT_RESTORE_OPTIONS = {
57
+ restore_ownership: false,
58
+ restore_permissions: true,
59
+ restore_times: true
60
+ }.freeze
61
+
64
62
  def reset!
65
63
  @_ran_once = false
66
64
  @unicode_names = false
@@ -68,9 +66,10 @@ module Zip
68
66
  @continue_on_exists_proc = false
69
67
  @sort_entries = false
70
68
  @default_compression = ::Zlib::DEFAULT_COMPRESSION
71
- @write_zip64_support = false
69
+ @write_zip64_support = true
72
70
  @warn_invalid_date = true
73
71
  @case_insensitive_match = false
72
+ @force_entry_names_encoding = nil
74
73
  @validate_entry_sizes = true
75
74
  end
76
75
 
data/rubyzip.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/zip/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'rubyzip'
7
+ s.version = ::Zip::VERSION
8
+ s.authors = ['Robert Haines', 'John Lees-Miller', 'Alexander Simonov']
9
+ s.email = [
10
+ 'hainesr@gmail.com', 'jdleesmiller@gmail.com', 'alex@simonov.me'
11
+ ]
12
+ s.homepage = 'http://github.com/rubyzip/rubyzip'
13
+ s.platform = Gem::Platform::RUBY
14
+ s.summary = 'rubyzip is a ruby module for reading and writing zip files'
15
+ s.files = Dir.glob('{samples,lib}/**/*.rb') +
16
+ %w[README.md Changelog.md Rakefile rubyzip.gemspec]
17
+ s.require_paths = ['lib']
18
+ s.license = 'BSD-2-Clause'
19
+
20
+ s.metadata = {
21
+ 'bug_tracker_uri' => 'https://github.com/rubyzip/rubyzip/issues',
22
+ 'changelog_uri' => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
23
+ 'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
24
+ 'source_code_uri' => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
25
+ 'wiki_uri' => 'https://github.com/rubyzip/rubyzip/wiki'
26
+ }
27
+
28
+ s.required_ruby_version = '>= 2.5'
29
+
30
+ s.add_development_dependency 'minitest', '~> 5.4'
31
+ s.add_development_dependency 'rake', '~> 12.3.3'
32
+ s.add_development_dependency 'rdoc', '~> 6.4.0'
33
+ s.add_development_dependency 'rubocop', '~> 1.12.0'
34
+ s.add_development_dependency 'rubocop-performance', '~> 1.10.0'
35
+ s.add_development_dependency 'rubocop-rake', '~> 0.5.0'
36
+ s.add_development_dependency 'simplecov', '~> 0.18.0'
37
+ s.add_development_dependency 'simplecov-lcov', '~> 0.8'
38
+ end