rubyzip 2.3.2 → 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 +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 -1
  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 -51
  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.2'
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,6 +35,11 @@ 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
44
  extend self
38
45
  attr_accessor :unicode_names,
@@ -46,6 +53,12 @@ module Zip
46
53
  :force_entry_names_encoding,
47
54
  :validate_entry_sizes
48
55
 
56
+ DEFAULT_RESTORE_OPTIONS = {
57
+ restore_ownership: false,
58
+ restore_permissions: true,
59
+ restore_times: true
60
+ }.freeze
61
+
49
62
  def reset!
50
63
  @_ran_once = false
51
64
  @unicode_names = false
@@ -53,9 +66,10 @@ module Zip
53
66
  @continue_on_exists_proc = false
54
67
  @sort_entries = false
55
68
  @default_compression = ::Zlib::DEFAULT_COMPRESSION
56
- @write_zip64_support = false
69
+ @write_zip64_support = true
57
70
  @warn_invalid_date = true
58
71
  @case_insensitive_match = false
72
+ @force_entry_names_encoding = nil
59
73
  @validate_entry_sizes = true
60
74
  end
61
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')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zip'
2
4
 
3
5
  # This is a simple example which uses rubyzip to
@@ -21,7 +23,7 @@ class ZipFileGenerator
21
23
  def write
22
24
  entries = Dir.entries(@input_dir) - %w[. ..]
23
25
 
24
- ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
26
+ ::Zip::File.open(@output_file, create: true) do |zipfile|
25
27
  write_entries entries, '', zipfile
26
28
  end
27
29
  end