rubyzip 2.3.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 +122 -39
  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 +41 -5
  16. data/lib/zip/entry.rb +273 -170
  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 +152 -221
  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 +6 -4
  36. data/lib/zip/input_stream.rb +43 -25
  37. data/lib/zip/ioextras/abstract_input_stream.rb +13 -8
  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 +45 -39
  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 -22
  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 +83 -35
  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,24 +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, offset = 0, decrypter = nil)
54
+ def initialize(context, offset: 0, decrypter: nil)
53
55
  super()
54
- @archive_io = get_io(context, offset)
55
- @decompressor = ::Zip::NullDecompressor
56
- @decrypter = decrypter || ::Zip::NullDecrypter.new
56
+ @archive_io = get_io(context, offset)
57
+ @decompressor = ::Zip::NullDecompressor
58
+ @decrypter = decrypter || ::Zip::NullDecrypter.new
57
59
  @current_entry = nil
60
+ @complete_entry = nil
58
61
  end
59
62
 
60
63
  def close
61
64
  @archive_io.close
62
65
  end
63
66
 
64
- # Returns a Entry object. It is necessary to call this
65
- # method on a newly created InputStream before reading from
66
- # the first entry in the archive. Returns nil when there are
67
- # 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.
68
71
  def get_next_entry
69
- @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
+
70
78
  open_entry
71
79
  end
72
80
 
@@ -85,12 +93,19 @@ module Zip
85
93
  @decompressor.read(length, outbuf)
86
94
  end
87
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
+
88
103
  class << self
89
104
  # Same as #initialize but if a block is passed the opened
90
105
  # stream is passed to the block and closed when the block
91
106
  # returns.
92
- def open(filename_or_io, offset = 0, decrypter = nil)
93
- zio = new(filename_or_io, offset, decrypter)
107
+ def open(filename_or_io, offset: 0, decrypter: nil)
108
+ zio = new(filename_or_io, offset: offset, decrypter: decrypter)
94
109
  return zio unless block_given?
95
110
 
96
111
  begin
@@ -100,9 +115,9 @@ module Zip
100
115
  end
101
116
  end
102
117
 
103
- def open_buffer(filename_or_io, offset = 0)
118
+ def open_buffer(filename_or_io, offset: 0)
104
119
  warn 'open_buffer is deprecated!!! Use open instead!'
105
- ::Zip::InputStream.open(filename_or_io, offset)
120
+ ::Zip::InputStream.open(filename_or_io, offset: offset)
106
121
  end
107
122
  end
108
123
 
@@ -122,17 +137,18 @@ module Zip
122
137
 
123
138
  def open_entry
124
139
  @current_entry = ::Zip::Entry.read_local_entry(@archive_io)
125
- if @current_entry && @current_entry.encrypted? && @decrypter.kind_of?(NullEncrypter)
126
- 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'
127
145
  end
128
146
 
129
- if @current_entry && @current_entry.incomplete? && @current_entry.crc == 0 \
130
- && @current_entry.compressed_size == 0 \
131
- && @current_entry.size == 0 && !@complete_entry
132
- raise GPFBit3Error,
133
- 'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
134
- '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
135
150
  end
151
+
136
152
  @decrypted_io = get_decrypted_io
137
153
  @decompressor = get_decompressor
138
154
  flush
@@ -150,16 +166,18 @@ module Zip
150
166
  return ::Zip::NullDecompressor if @current_entry.nil?
151
167
 
152
168
  decompressed_size =
153
- 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
154
171
  @complete_entry.size
155
172
  else
156
173
  @current_entry.size
157
174
  end
158
175
 
159
- 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
+ )
160
179
  if decompressor_class.nil?
161
- raise ::Zip::CompressionMethodError,
162
- "Unsupported compression method #{@current_entry.compression_method}"
180
+ raise ::Zip::CompressionMethodError, @current_entry.compression_method
163
181
  end
164
182
 
165
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,15 +13,15 @@ module Zip
11
13
  super
12
14
  @lineno = 0
13
15
  @pos = 0
14
- @output_buffer = ''
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 = '')
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
@@ -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 = ''
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, '')) 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, ''))
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,48 +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, stream = false, encrypter = nil)
32
+ def initialize(file_name, stream: false, encrypter: nil)
28
33
  super()
29
34
  @file_name = file_name
30
35
  @output_stream = if stream
31
- iostream = @file_name.dup
36
+ iostream = Zip::RUNNING_ON_WINDOWS ? @file_name : @file_name.dup
32
37
  iostream.reopen(@file_name)
33
38
  iostream.rewind
34
39
  iostream
35
40
  else
36
41
  ::File.new(@file_name, 'wb')
37
42
  end
38
- @entry_set = ::Zip::EntrySet.new
43
+ @cdir = ::Zip::CentralDirectory.new
39
44
  @compressor = ::Zip::NullCompressor.instance
40
45
  @encrypter = encrypter || ::Zip::NullEncrypter.new
41
46
  @closed = false
42
47
  @current_entry = nil
43
- @comment = nil
44
48
  end
45
49
 
46
50
  # Same as #initialize but if a block is passed the opened
47
51
  # stream is passed to the block and closed when the block
48
52
  # returns.
49
53
  class << self
50
- def open(file_name, encrypter = nil)
54
+ def open(file_name, encrypter: nil)
51
55
  return new(file_name) unless block_given?
52
56
 
53
- zos = new(file_name, false, encrypter)
57
+ zos = new(file_name, stream: false, encrypter: encrypter)
54
58
  yield zos
55
59
  ensure
56
60
  zos.close if zos
57
61
  end
58
62
 
59
63
  # Same as #open but writes to a filestream instead
60
- def write_buffer(io = ::StringIO.new(''), encrypter = nil)
64
+ def write_buffer(io = ::StringIO.new, encrypter: nil)
61
65
  io.binmode if io.respond_to?(:binmode)
62
- zos = new(io, true, encrypter)
66
+ zos = new(io, stream: true, encrypter: encrypter)
63
67
  yield zos
64
68
  zos.close_buffer
65
69
  end
@@ -71,7 +75,7 @@ module Zip
71
75
 
72
76
  finalize_current_entry
73
77
  update_local_headers
74
- write_central_directory
78
+ @cdir.write_to_stream(@output_stream)
75
79
  @output_stream.close
76
80
  @closed = true
77
81
  end
@@ -82,27 +86,31 @@ module Zip
82
86
 
83
87
  finalize_current_entry
84
88
  update_local_headers
85
- write_central_directory
89
+ @cdir.write_to_stream(@output_stream)
86
90
  @closed = true
91
+ @output_stream.flush
87
92
  @output_stream
88
93
  end
89
94
 
90
95
  # Closes the current entry and opens a new for writing.
91
96
  # +entry+ can be a ZipEntry object or a string.
92
- 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
+ )
93
101
  raise Error, 'zip stream is closed' if @closed
94
102
 
95
- new_entry = if entry_name.kind_of?(Entry)
96
- entry_name
97
- else
98
- Entry.new(@file_name, entry_name.to_s)
99
- end
100
- new_entry.comment = comment unless comment.nil?
101
- unless extra.nil?
102
- new_entry.extra = extra.kind_of?(ExtraField) ? extra : ExtraField.new(extra.to_s)
103
- end
104
- new_entry.compression_method = compression_method unless compression_method.nil?
105
- 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)
106
114
  @current_entry = new_entry
107
115
  end
108
116
 
@@ -112,7 +120,7 @@ module Zip
112
120
  raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
113
121
 
114
122
  finalize_current_entry
115
- @entry_set << entry
123
+ @cdir << entry
116
124
  src_pos = entry.local_header_offset
117
125
  entry.write_local_entry(@output_stream)
118
126
  @compressor = NullCompressor.instance
@@ -136,47 +144,45 @@ module Zip
136
144
  @current_entry.calculate_local_header_size
137
145
  @current_entry.size = @compressor.size
138
146
  @current_entry.crc = @compressor.crc
139
- @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
+ )
140
152
  @current_entry.gp_flags |= @encrypter.gp_flags
141
153
  @current_entry = nil
142
154
  @compressor = ::Zip::NullCompressor.instance
143
155
  end
144
156
 
145
- def init_next_entry(entry, level = Zip.default_compression)
157
+ def init_next_entry(entry)
146
158
  finalize_current_entry
147
- @entry_set << entry
159
+ @cdir << entry
148
160
  entry.write_local_entry(@output_stream)
149
161
  @encrypter.reset!
150
162
  @output_stream << @encrypter.header(entry.mtime)
151
- @compressor = get_compressor(entry, level)
163
+ @compressor = get_compressor(entry)
152
164
  end
153
165
 
154
- def get_compressor(entry, level)
166
+ def get_compressor(entry)
155
167
  case entry.compression_method
156
168
  when Entry::DEFLATED
157
- ::Zip::Deflater.new(@output_stream, level, @encrypter)
169
+ ::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
158
170
  when Entry::STORED
159
171
  ::Zip::PassThruCompressor.new(@output_stream)
160
172
  else
161
- raise ::Zip::CompressionMethodError,
162
- "Invalid compression method: '#{entry.compression_method}'"
173
+ raise ::Zip::CompressionMethodError, entry.compression_method
163
174
  end
164
175
  end
165
176
 
166
177
  def update_local_headers
167
178
  pos = @output_stream.pos
168
- @entry_set.each do |entry|
179
+ @cdir.each do |entry|
169
180
  @output_stream.pos = entry.local_header_offset
170
- entry.write_local_entry(@output_stream, true)
181
+ entry.write_local_entry(@output_stream, rewrite: true)
171
182
  end
172
183
  @output_stream.pos = pos
173
184
  end
174
185
 
175
- def write_central_directory
176
- cdir = CentralDirectory.new(@entry_set, @comment)
177
- cdir.write_to_stream(@output_stream)
178
- end
179
-
180
186
  protected
181
187
 
182
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 = '')
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.3.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
- BANNER = [
38
- 'RubyZip 3.0 is coming!',
39
- '**********************',
40
- '',
41
- 'The public API of some Rubyzip classes has been modernized to use named',
42
- 'parameters for optional arguments. Please check your usage of the',
43
- 'following classes:',
44
- ' * `Zip::File`',
45
- ' * `Zip::Entry`',
46
- ' * `Zip::InputStream`',
47
- ' * `Zip::OutputStream`',
48
- '',
49
- 'Please ensure that your Gemfiles and .gemspecs are suitably restrictive',
50
- 'to avoid an unexpected breakage when 3.0 is released (e.g. ~> 2.3.0).',
51
- 'See https://github.com/rubyzip/rubyzip for details. The Changelog also',
52
- 'lists other enhancements and bugfixes that have been implemented since',
53
- 'version 2.3.0.'
54
- ].freeze
55
-
56
44
  extend self
57
45
  attr_accessor :unicode_names,
58
46
  :on_exists_proc,
@@ -65,18 +53,23 @@ module Zip
65
53
  :force_entry_names_encoding,
66
54
  :validate_entry_sizes
67
55
 
68
- def reset!
69
- warn BANNER.join("\n") unless BANNER.empty?
56
+ DEFAULT_RESTORE_OPTIONS = {
57
+ restore_ownership: false,
58
+ restore_permissions: true,
59
+ restore_times: true
60
+ }.freeze
70
61
 
62
+ def reset!
71
63
  @_ran_once = false
72
64
  @unicode_names = false
73
65
  @on_exists_proc = false
74
66
  @continue_on_exists_proc = false
75
67
  @sort_entries = false
76
68
  @default_compression = ::Zlib::DEFAULT_COMPRESSION
77
- @write_zip64_support = false
69
+ @write_zip64_support = true
78
70
  @warn_invalid_date = true
79
71
  @case_insensitive_match = false
72
+ @force_entry_names_encoding = nil
80
73
  @validate_entry_sizes = true
81
74
  end
82
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
data/samples/example.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  $LOAD_PATH << '../lib'
4
5
  system('zip example.zip example.rb gtk_ruby_zip.rb')
@@ -20,7 +21,8 @@ end
20
21
 
21
22
  zf = Zip::File.new('example.zip')
22
23
  zf.each_with_index do |entry, index|
23
- puts "entry #{index} is #{entry.name}, size = #{entry.size}, compressed size = #{entry.compressed_size}"
24
+ puts "entry #{index} is #{entry.name}, size = #{entry.size}, " \
25
+ "compressed size = #{entry.compressed_size}"
24
26
  # use zf.get_input_stream(entry) to get a ZipInputStream for the entry
25
27
  # entry can be the ZipEntry object or any object which has a to_s method that
26
28
  # returns the name of the entry.
@@ -70,8 +72,11 @@ part_zips_count = Zip::File.split('large_zip_file.zip', 2_097_152, false)
70
72
  puts "Zip file splitted in #{part_zips_count} parts"
71
73
 
72
74
  # Track splitting an archive
73
- Zip::File.split('large_zip_file.zip', 1_048_576, true, 'part_zip_file') do |part_count, part_index, chunk_bytes, segment_bytes|
74
- puts "#{part_index} of #{part_count} part splitting: #{(chunk_bytes.to_f / segment_bytes * 100).to_i}%"
75
+ Zip::File.split(
76
+ 'large_zip_file.zip', 1_048_576, true, 'part_zip_file'
77
+ ) do |part_count, part_index, chunk_bytes, segment_bytes|
78
+ puts "#{part_index} of #{part_count} part splitting: " \
79
+ "#{(chunk_bytes.to_f / segment_bytes * 100).to_i}%"
75
80
  end
76
81
 
77
82
  # For other examples, look at zip.rb and ziptest.rb
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  $LOAD_PATH << '../lib'
4
5
 
@@ -8,7 +9,7 @@ EXAMPLE_ZIP = 'filesystem.zip'
8
9
 
9
10
  File.delete(EXAMPLE_ZIP) if File.exist?(EXAMPLE_ZIP)
10
11
 
11
- Zip::File.open(EXAMPLE_ZIP, Zip::File::CREATE) do |zf|
12
+ Zip::File.open(EXAMPLE_ZIP, create: true) do |zf|
12
13
  zf.file.open('file1.txt', 'w') { |os| os.write 'first file1.txt' }
13
14
  zf.dir.mkdir('dir1')
14
15
  zf.dir.chdir('dir1')