rubyzip 2.4.1 → 3.0.0.alpha

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.
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 +262 -198
  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 +144 -265
  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 -20
  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 +84 -50
  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.1'
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,26 +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' (from %s).
39
- This method is changing or deprecated 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
- return unless ENV['RUBYZIP_V3_API_WARN']
46
-
47
- loc = caller_locations(2, 1)[0]
48
- from = "#{loc.path.split('/').last}:#{loc.lineno}"
49
- warn format(V3_API_WARNING_MSG, method, from)
50
- end
51
-
52
- if ENV['RUBYZIP_V3_API_WARN'] && RUBY_VERSION < '3.0'
53
- warn 'RubyZip 3.0 will require Ruby 3.0 or later.'
54
- end
55
-
56
44
  extend self
57
45
  attr_accessor :unicode_names,
58
46
  :on_exists_proc,
@@ -65,6 +53,12 @@ module Zip
65
53
  :force_entry_names_encoding,
66
54
  :validate_entry_sizes
67
55
 
56
+ DEFAULT_RESTORE_OPTIONS = {
57
+ restore_ownership: false,
58
+ restore_permissions: true,
59
+ restore_times: true
60
+ }.freeze
61
+
68
62
  def reset!
69
63
  @_ran_once = false
70
64
  @unicode_names = false
@@ -72,9 +66,10 @@ module Zip
72
66
  @continue_on_exists_proc = false
73
67
  @sort_entries = false
74
68
  @default_compression = ::Zlib::DEFAULT_COMPRESSION
75
- @write_zip64_support = false
69
+ @write_zip64_support = true
76
70
  @warn_invalid_date = true
77
71
  @case_insensitive_match = false
72
+ @force_entry_names_encoding = nil
78
73
  @validate_entry_sizes = true
79
74
  end
80
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