rubyzip 1.3.0 → 2.4.1

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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -16
  3. data/Rakefile +3 -0
  4. data/lib/zip/central_directory.rb +9 -5
  5. data/lib/zip/constants.rb +52 -0
  6. data/lib/zip/crypto/decrypted_io.rb +40 -0
  7. data/lib/zip/crypto/traditional_encryption.rb +9 -9
  8. data/lib/zip/decompressor.rb +19 -1
  9. data/lib/zip/dos_time.rb +24 -12
  10. data/lib/zip/entry.rb +107 -49
  11. data/lib/zip/entry_set.rb +2 -0
  12. data/lib/zip/errors.rb +1 -0
  13. data/lib/zip/extra_field/generic.rb +10 -9
  14. data/lib/zip/extra_field/ntfs.rb +5 -1
  15. data/lib/zip/extra_field/old_unix.rb +3 -1
  16. data/lib/zip/extra_field/universal_time.rb +42 -12
  17. data/lib/zip/extra_field/unix.rb +3 -1
  18. data/lib/zip/extra_field/zip64.rb +5 -3
  19. data/lib/zip/extra_field.rb +11 -9
  20. data/lib/zip/file.rb +142 -65
  21. data/lib/zip/filesystem.rb +193 -177
  22. data/lib/zip/inflater.rb +24 -36
  23. data/lib/zip/input_stream.rb +50 -30
  24. data/lib/zip/ioextras/abstract_input_stream.rb +23 -12
  25. data/lib/zip/ioextras/abstract_output_stream.rb +1 -1
  26. data/lib/zip/ioextras.rb +3 -3
  27. data/lib/zip/null_decompressor.rb +1 -9
  28. data/lib/zip/output_stream.rb +28 -12
  29. data/lib/zip/pass_thru_compressor.rb +2 -2
  30. data/lib/zip/pass_thru_decompressor.rb +13 -22
  31. data/lib/zip/streamable_directory.rb +3 -3
  32. data/lib/zip/streamable_stream.rb +6 -10
  33. data/lib/zip/version.rb +1 -1
  34. data/lib/zip.rb +23 -3
  35. data/samples/example.rb +2 -2
  36. data/samples/example_filesystem.rb +1 -1
  37. data/samples/gtk_ruby_zip.rb +19 -19
  38. data/samples/qtzip.rb +6 -6
  39. data/samples/write_simple.rb +2 -4
  40. data/samples/zipfind.rb +23 -22
  41. metadata +54 -181
  42. data/test/basic_zip_file_test.rb +0 -60
  43. data/test/case_sensitivity_test.rb +0 -69
  44. data/test/central_directory_entry_test.rb +0 -69
  45. data/test/central_directory_test.rb +0 -100
  46. data/test/crypto/null_encryption_test.rb +0 -57
  47. data/test/crypto/traditional_encryption_test.rb +0 -80
  48. data/test/data/WarnInvalidDate.zip +0 -0
  49. data/test/data/file1.txt +0 -46
  50. data/test/data/file1.txt.deflatedData +0 -0
  51. data/test/data/file2.txt +0 -1504
  52. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  53. data/test/data/globTest/foo.txt +0 -0
  54. data/test/data/globTest/food.txt +0 -0
  55. data/test/data/globTest.zip +0 -0
  56. data/test/data/gpbit3stored.zip +0 -0
  57. data/test/data/mimetype +0 -1
  58. data/test/data/notzippedruby.rb +0 -7
  59. data/test/data/ntfs.zip +0 -0
  60. data/test/data/oddExtraField.zip +0 -0
  61. data/test/data/path_traversal/Makefile +0 -10
  62. data/test/data/path_traversal/jwilk/README.md +0 -5
  63. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  64. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  65. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  66. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  67. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  68. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  69. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  70. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  71. data/test/data/path_traversal/relative1.zip +0 -0
  72. data/test/data/path_traversal/tilde.zip +0 -0
  73. data/test/data/path_traversal/tuzovakaoff/README.md +0 -3
  74. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  75. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  76. data/test/data/rubycode.zip +0 -0
  77. data/test/data/rubycode2.zip +0 -0
  78. data/test/data/test.xls +0 -0
  79. data/test/data/testDirectory.bin +0 -0
  80. data/test/data/zip64-sample.zip +0 -0
  81. data/test/data/zipWithDirs.zip +0 -0
  82. data/test/data/zipWithEncryption.zip +0 -0
  83. data/test/deflater_test.rb +0 -65
  84. data/test/encryption_test.rb +0 -42
  85. data/test/entry_set_test.rb +0 -163
  86. data/test/entry_test.rb +0 -154
  87. data/test/errors_test.rb +0 -35
  88. data/test/extra_field_test.rb +0 -76
  89. data/test/file_extract_directory_test.rb +0 -54
  90. data/test/file_extract_test.rb +0 -145
  91. data/test/file_permissions_test.rb +0 -65
  92. data/test/file_split_test.rb +0 -57
  93. data/test/file_test.rb +0 -666
  94. data/test/filesystem/dir_iterator_test.rb +0 -58
  95. data/test/filesystem/directory_test.rb +0 -139
  96. data/test/filesystem/file_mutating_test.rb +0 -87
  97. data/test/filesystem/file_nonmutating_test.rb +0 -508
  98. data/test/filesystem/file_stat_test.rb +0 -64
  99. data/test/gentestfiles.rb +0 -126
  100. data/test/inflater_test.rb +0 -14
  101. data/test/input_stream_test.rb +0 -182
  102. data/test/ioextras/abstract_input_stream_test.rb +0 -102
  103. data/test/ioextras/abstract_output_stream_test.rb +0 -106
  104. data/test/ioextras/fake_io_test.rb +0 -18
  105. data/test/local_entry_test.rb +0 -154
  106. data/test/output_stream_test.rb +0 -128
  107. data/test/pass_thru_compressor_test.rb +0 -30
  108. data/test/pass_thru_decompressor_test.rb +0 -14
  109. data/test/path_traversal_test.rb +0 -141
  110. data/test/samples/example_recursive_test.rb +0 -37
  111. data/test/settings_test.rb +0 -95
  112. data/test/test_helper.rb +0 -234
  113. data/test/unicode_file_names_and_comments_test.rb +0 -62
  114. data/test/zip64_full_test.rb +0 -51
  115. data/test/zip64_support_test.rb +0 -14
data/lib/zip/inflater.rb CHANGED
@@ -1,64 +1,52 @@
1
1
  module Zip
2
2
  class Inflater < Decompressor #:nodoc:all
3
- def initialize(input_stream, decrypter = NullDecrypter.new)
4
- super(input_stream)
5
- @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
6
- @output_buffer = ''.dup
7
- @has_returned_empty_string = false
8
- @decrypter = decrypter
9
- end
3
+ def initialize(*args)
4
+ super
10
5
 
11
- def sysread(number_of_bytes = nil, buf = '')
12
- readEverything = number_of_bytes.nil?
13
- while readEverything || @output_buffer.bytesize < number_of_bytes
14
- break if internal_input_finished?
15
- @output_buffer << internal_produce_input(buf)
16
- end
17
- return value_when_finished if @output_buffer.bytesize == 0 && input_finished?
18
- end_index = number_of_bytes.nil? ? @output_buffer.bytesize : number_of_bytes
19
- @output_buffer.slice!(0...end_index)
6
+ @buffer = ''.b
7
+ @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
20
8
  end
21
9
 
22
- def produce_input
23
- if @output_buffer.empty?
24
- internal_produce_input
25
- else
26
- @output_buffer.slice!(0...(@output_buffer.length))
10
+ def read(length = nil, outbuf = ''.b)
11
+ return (length.nil? || length.zero? ? '' : nil) if eof
12
+
13
+ while length.nil? || (@buffer.bytesize < length)
14
+ break if input_finished?
15
+
16
+ @buffer << produce_input
27
17
  end
18
+
19
+ outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
28
20
  end
29
21
 
30
- # to be used with produce_input, not read (as read may still have more data cached)
31
- # is data cached anywhere other than @outputBuffer? the comment above may be wrong
32
- def input_finished?
33
- @output_buffer.empty? && internal_input_finished?
22
+ def eof
23
+ @buffer.empty? && input_finished?
34
24
  end
35
25
 
36
- alias :eof input_finished?
37
- alias :eof? input_finished?
26
+ alias eof? eof
38
27
 
39
28
  private
40
29
 
41
- def internal_produce_input(buf = '')
30
+ def produce_input
42
31
  retried = 0
43
32
  begin
44
- @zlib_inflater.inflate(@decrypter.decrypt(@input_stream.read(Decompressor::CHUNK_SIZE, buf)))
33
+ @zlib_inflater.inflate(input_stream.read(Decompressor::CHUNK_SIZE))
45
34
  rescue Zlib::BufError
46
35
  raise if retried >= 5 # how many times should we retry?
36
+
47
37
  retried += 1
48
38
  retry
49
39
  end
40
+ rescue Zlib::Error
41
+ raise(::Zip::DecompressionError, 'zlib error while inflating')
50
42
  end
51
43
 
52
- def internal_input_finished?
44
+ def input_finished?
53
45
  @zlib_inflater.finished?
54
46
  end
55
-
56
- def value_when_finished # mimic behaviour of ruby File object.
57
- return if @has_returned_empty_string
58
- @has_returned_empty_string = true
59
- ''
60
- end
61
47
  end
48
+
49
+ ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_DEFLATE, ::Zip::Inflater)
62
50
  end
63
51
 
64
52
  # Copyright (C) 2002, 2003 Thomas Sondergaard
@@ -39,6 +39,8 @@ module Zip
39
39
  # class.
40
40
 
41
41
  class InputStream
42
+ CHUNK_SIZE = 32_768
43
+
42
44
  include ::Zip::IOExtras::AbstractInputStream
43
45
 
44
46
  # Opens the indicated zip file. An exception is thrown
@@ -47,11 +49,17 @@ module Zip
47
49
  #
48
50
  # @param context [String||IO||StringIO] file path or IO/StringIO object
49
51
  # @param offset [Integer] offset in the IO/StringIO
50
- def initialize(context, offset = 0, decrypter = nil)
52
+ def initialize(context, dep_offset = 0, dep_decrypter = nil, offset: 0, decrypter: nil)
51
53
  super()
52
- @archive_io = get_io(context, offset)
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)
53
61
  @decompressor = ::Zip::NullDecompressor
54
- @decrypter = decrypter || ::Zip::NullDecrypter.new
62
+ @decrypter = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
55
63
  @current_entry = nil
56
64
  end
57
65
 
@@ -71,6 +79,7 @@ module Zip
71
79
  # Rewinds the stream to the beginning of the current entry
72
80
  def rewind
73
81
  return if @current_entry.nil?
82
+
74
83
  @lineno = 0
75
84
  @pos = 0
76
85
  @archive_io.seek(@current_entry.local_header_offset, IO::SEEK_SET)
@@ -78,23 +87,24 @@ module Zip
78
87
  end
79
88
 
80
89
  # Modeled after IO.sysread
81
- def sysread(number_of_bytes = nil, buf = nil)
82
- @decompressor.sysread(number_of_bytes, buf)
90
+ def sysread(length = nil, outbuf = '')
91
+ @decompressor.read(length, outbuf)
83
92
  end
84
93
 
85
- def eof
86
- @output_buffer.empty? && @decompressor.eof
87
- end
88
-
89
- alias :eof? eof
90
-
91
94
  class << self
92
95
  # Same as #initialize but if a block is passed the opened
93
96
  # stream is passed to the block and closed when the block
94
97
  # returns.
95
- def open(filename_or_io, offset = 0, decrypter = nil)
96
- zio = new(filename_or_io, offset, decrypter)
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)
97
106
  return zio unless block_given?
107
+
98
108
  begin
99
109
  yield zio
100
110
  ensure
@@ -103,8 +113,9 @@ module Zip
103
113
  end
104
114
 
105
115
  def open_buffer(filename_or_io, offset = 0)
106
- puts 'open_buffer is deprecated!!! Use open instead!'
107
- open(filename_or_io, offset)
116
+ Zip.warn_about_v3_api('Zip::InputStream.open_buffer')
117
+
118
+ ::Zip::InputStream.open(filename_or_io, offset)
108
119
  end
109
120
  end
110
121
 
@@ -124,46 +135,55 @@ module Zip
124
135
 
125
136
  def open_entry
126
137
  @current_entry = ::Zip::Entry.read_local_entry(@archive_io)
127
- if @current_entry && @current_entry.gp_flags & 1 == 1 && @decrypter.is_a?(NullEncrypter)
138
+ if @current_entry && @current_entry.encrypted? && @decrypter.kind_of?(NullEncrypter)
128
139
  raise Error, 'password required to decode zip file'
129
140
  end
130
- if @current_entry && @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 \
141
+
142
+ if @current_entry && @current_entry.incomplete? && @current_entry.crc == 0 \
131
143
  && @current_entry.compressed_size == 0 \
132
144
  && @current_entry.size == 0 && !@complete_entry
133
145
  raise GPFBit3Error,
134
146
  'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
135
147
  'Please use ::Zip::File instead of ::Zip::InputStream'
136
148
  end
149
+ @decrypted_io = get_decrypted_io
137
150
  @decompressor = get_decompressor
138
151
  flush
139
152
  @current_entry
140
153
  end
141
154
 
155
+ def get_decrypted_io
156
+ header = @archive_io.read(@decrypter.header_bytesize)
157
+ @decrypter.reset!(header)
158
+
159
+ ::Zip::DecryptedIo.new(@archive_io, @decrypter)
160
+ end
161
+
142
162
  def get_decompressor
143
- if @current_entry.nil?
144
- ::Zip::NullDecompressor
145
- elsif @current_entry.compression_method == ::Zip::Entry::STORED
146
- if @current_entry.gp_flags & 8 == 8 && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
147
- ::Zip::PassThruDecompressor.new(@archive_io, @complete_entry.size)
163
+ return ::Zip::NullDecompressor if @current_entry.nil?
164
+
165
+ decompressed_size =
166
+ if @current_entry.incomplete? && @current_entry.crc == 0 && @current_entry.size == 0 && @complete_entry
167
+ @complete_entry.size
148
168
  else
149
- ::Zip::PassThruDecompressor.new(@archive_io, @current_entry.size)
169
+ @current_entry.size
150
170
  end
151
- elsif @current_entry.compression_method == ::Zip::Entry::DEFLATED
152
- header = @archive_io.read(@decrypter.header_bytesize)
153
- @decrypter.reset!(header)
154
- ::Zip::Inflater.new(@archive_io, @decrypter)
155
- else
171
+
172
+ decompressor_class = ::Zip::Decompressor.find_by_compression_method(@current_entry.compression_method)
173
+ if decompressor_class.nil?
156
174
  raise ::Zip::CompressionMethodError,
157
175
  "Unsupported compression method #{@current_entry.compression_method}"
158
176
  end
177
+
178
+ decompressor_class.new(@decrypted_io, decompressed_size)
159
179
  end
160
180
 
161
181
  def produce_input
162
- @decompressor.produce_input
182
+ @decompressor.read(CHUNK_SIZE)
163
183
  end
164
184
 
165
185
  def input_finished?
166
- @decompressor.input_finished?
186
+ @decompressor.eof
167
187
  end
168
188
  end
169
189
  end
@@ -11,13 +11,13 @@ module Zip
11
11
  super
12
12
  @lineno = 0
13
13
  @pos = 0
14
- @output_buffer = ''
14
+ @output_buffer = ''.b
15
15
  end
16
16
 
17
17
  attr_accessor :lineno
18
18
  attr_reader :pos
19
19
 
20
- def read(number_of_bytes = nil, buf = '')
20
+ def read(number_of_bytes = nil, buf = ''.b)
21
21
  tbuf = if @output_buffer.bytesize > 0
22
22
  if number_of_bytes <= @output_buffer.bytesize
23
23
  @output_buffer.slice!(0, number_of_bytes)
@@ -26,7 +26,7 @@ module Zip
26
26
  rbuf = sysread(number_of_bytes, buf)
27
27
  out = @output_buffer
28
28
  out << rbuf if rbuf
29
- @output_buffer = ''
29
+ @output_buffer = ''.b
30
30
  out
31
31
  end
32
32
  else
@@ -35,6 +35,7 @@ module Zip
35
35
 
36
36
  if tbuf.nil? || tbuf.empty?
37
37
  return nil if number_of_bytes
38
+
38
39
  return ''
39
40
  end
40
41
 
@@ -48,13 +49,13 @@ module Zip
48
49
  buf
49
50
  end
50
51
 
51
- def readlines(a_sep_string = $/)
52
+ def readlines(a_sep_string = $INPUT_RECORD_SEPARATOR)
52
53
  ret_val = []
53
54
  each_line(a_sep_string) { |line| ret_val << line }
54
55
  ret_val
55
56
  end
56
57
 
57
- def gets(a_sep_string = $/, number_of_bytes = nil)
58
+ def gets(a_sep_string = $INPUT_RECORD_SEPARATOR, number_of_bytes = nil)
58
59
  @lineno = @lineno.next
59
60
 
60
61
  if number_of_bytes.respond_to?(:to_int)
@@ -62,20 +63,22 @@ module Zip
62
63
  a_sep_string = a_sep_string.to_str if a_sep_string
63
64
  elsif a_sep_string.respond_to?(:to_int)
64
65
  number_of_bytes = a_sep_string.to_int
65
- a_sep_string = $/
66
+ a_sep_string = $INPUT_RECORD_SEPARATOR
66
67
  else
67
68
  number_of_bytes = nil
68
69
  a_sep_string = a_sep_string.to_str if a_sep_string
69
70
  end
70
71
 
71
72
  return read(number_of_bytes) if a_sep_string.nil?
72
- a_sep_string = "#{$/}#{$/}" if a_sep_string.empty?
73
+
74
+ a_sep_string = "#{$INPUT_RECORD_SEPARATOR}#{$INPUT_RECORD_SEPARATOR}" if a_sep_string.empty?
73
75
 
74
76
  buffer_index = 0
75
77
  over_limit = (number_of_bytes && @output_buffer.bytesize >= number_of_bytes)
76
78
  while (match_index = @output_buffer.index(a_sep_string, buffer_index)).nil? && !over_limit
77
79
  buffer_index = [buffer_index, @output_buffer.bytesize - a_sep_string.bytesize].max
78
80
  return @output_buffer.empty? ? nil : flush if input_finished?
81
+
79
82
  @output_buffer << produce_input
80
83
  over_limit = (number_of_bytes && @output_buffer.bytesize >= number_of_bytes)
81
84
  end
@@ -90,22 +93,30 @@ module Zip
90
93
 
91
94
  def flush
92
95
  ret_val = @output_buffer
93
- @output_buffer = ''
96
+ @output_buffer = ''.b
94
97
  ret_val
95
98
  end
96
99
 
97
- def readline(a_sep_string = $/)
100
+ def readline(a_sep_string = $INPUT_RECORD_SEPARATOR)
98
101
  ret_val = gets(a_sep_string)
99
102
  raise EOFError unless ret_val
103
+
100
104
  ret_val
101
105
  end
102
106
 
103
- def each_line(a_sep_string = $/)
104
- yield readline(a_sep_string) while true
107
+ def each_line(a_sep_string = $INPUT_RECORD_SEPARATOR)
108
+ loop { yield readline(a_sep_string) }
105
109
  rescue EOFError
110
+ # We just need to catch this; we don't need to handle it.
111
+ end
112
+
113
+ alias each each_line
114
+
115
+ def eof
116
+ @output_buffer.empty? && input_finished?
106
117
  end
107
118
 
108
- alias_method :each, :each_line
119
+ alias eof? eof
109
120
  end
110
121
  end
111
122
  end
@@ -11,7 +11,7 @@ module Zip
11
11
  end
12
12
 
13
13
  def print(*params)
14
- self << params.join($,) << $\.to_s
14
+ self << params.join($OUTPUT_FIELD_SEPARATOR) << $OUTPUT_RECORD_SEPARATOR.to_s
15
15
  end
16
16
 
17
17
  def printf(a_format_string, *params)
data/lib/zip/ioextras.rb CHANGED
@@ -6,14 +6,14 @@ module Zip
6
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, ''.b)) 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, ''.b))
17
17
  toread -= tr
18
18
  end
19
19
  end
@@ -25,7 +25,7 @@ module Zip
25
25
  object == IO || super
26
26
  end
27
27
  end
28
- end # IOExtras namespace module
28
+ end
29
29
  end
30
30
 
31
31
  require 'zip/ioextras/abstract_input_stream'
@@ -2,18 +2,10 @@ module Zip
2
2
  module NullDecompressor #:nodoc:all
3
3
  module_function
4
4
 
5
- def sysread(_numberOfBytes = nil, _buf = nil)
5
+ def read(_length = nil, _outbuf = nil)
6
6
  nil
7
7
  end
8
8
 
9
- def produce_input
10
- nil
11
- end
12
-
13
- def input_finished?
14
- true
15
- end
16
-
17
9
  def eof
18
10
  true
19
11
  end
@@ -24,10 +24,13 @@ module Zip
24
24
 
25
25
  # Opens the indicated zip file. If a file with that name already
26
26
  # exists it will be overwritten.
27
- def initialize(file_name, stream = false, encrypter = nil)
27
+ def initialize(file_name, dep_stream = false, dep_encrypter = nil, stream: false, encrypter: nil)
28
28
  super()
29
+
30
+ Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
31
+
29
32
  @file_name = file_name
30
- @output_stream = if stream
33
+ @output_stream = if stream || dep_stream
31
34
  iostream = @file_name.dup
32
35
  iostream.reopen(@file_name)
33
36
  iostream.rewind
@@ -37,7 +40,7 @@ module Zip
37
40
  end
38
41
  @entry_set = ::Zip::EntrySet.new
39
42
  @compressor = ::Zip::NullCompressor.instance
40
- @encrypter = encrypter || ::Zip::NullEncrypter.new
43
+ @encrypter = encrypter || dep_encrypter || ::Zip::NullEncrypter.new
41
44
  @closed = false
42
45
  @current_entry = nil
43
46
  @comment = nil
@@ -47,17 +50,23 @@ module Zip
47
50
  # stream is passed to the block and closed when the block
48
51
  # returns.
49
52
  class << self
50
- def open(file_name, encrypter = nil)
53
+ def open(file_name, dep_encrypter = nil, encrypter: nil)
51
54
  return new(file_name) unless block_given?
52
- zos = new(file_name, false, encrypter)
55
+
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))
53
59
  yield zos
54
60
  ensure
55
61
  zos.close if zos
56
62
  end
57
63
 
58
64
  # Same as #open but writes to a filestream instead
59
- def write_buffer(io = ::StringIO.new(''), encrypter = nil)
60
- zos = new(io, true, encrypter)
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
+
68
+ io.binmode if io.respond_to?(:binmode)
69
+ zos = new(io, stream: true, encrypter: (encrypter || dep_encrypter))
61
70
  yield zos
62
71
  zos.close_buffer
63
72
  end
@@ -66,6 +75,7 @@ module Zip
66
75
  # Closes the stream and writes the central directory to the zip file
67
76
  def close
68
77
  return if @closed
78
+
69
79
  finalize_current_entry
70
80
  update_local_headers
71
81
  write_central_directory
@@ -76,6 +86,7 @@ module Zip
76
86
  # Closes the stream and writes the central directory to the zip file
77
87
  def close_buffer
78
88
  return @output_stream if @closed
89
+
79
90
  finalize_current_entry
80
91
  update_local_headers
81
92
  write_central_directory
@@ -87,6 +98,7 @@ module Zip
87
98
  # +entry+ can be a ZipEntry object or a string.
88
99
  def put_next_entry(entry_name, comment = nil, extra = nil, compression_method = Entry::DEFLATED, level = Zip.default_compression)
89
100
  raise Error, 'zip stream is closed' if @closed
101
+
90
102
  new_entry = if entry_name.kind_of?(Entry)
91
103
  entry_name
92
104
  else
@@ -94,7 +106,7 @@ module Zip
94
106
  end
95
107
  new_entry.comment = comment unless comment.nil?
96
108
  unless extra.nil?
97
- new_entry.extra = extra.is_a?(ExtraField) ? extra : ExtraField.new(extra.to_s)
109
+ new_entry.extra = extra.kind_of?(ExtraField) ? extra : ExtraField.new(extra.to_s)
98
110
  end
99
111
  new_entry.compression_method = compression_method unless compression_method.nil?
100
112
  init_next_entry(new_entry, level)
@@ -104,7 +116,8 @@ module Zip
104
116
  def copy_raw_entry(entry)
105
117
  entry = entry.dup
106
118
  raise Error, 'zip stream is closed' if @closed
107
- raise Error, 'entry is not a ZipEntry' unless entry.is_a?(Entry)
119
+ raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
120
+
108
121
  finalize_current_entry
109
122
  @entry_set << entry
110
123
  src_pos = entry.local_header_offset
@@ -123,8 +136,11 @@ module Zip
123
136
 
124
137
  def finalize_current_entry
125
138
  return unless @current_entry
139
+
126
140
  finish
127
- @current_entry.compressed_size = @output_stream.tell - @current_entry.local_header_offset - @current_entry.calculate_local_header_size
141
+ @current_entry.compressed_size = @output_stream.tell - \
142
+ @current_entry.local_header_offset - \
143
+ @current_entry.calculate_local_header_size
128
144
  @current_entry.size = @compressor.size
129
145
  @current_entry.crc = @compressor.crc
130
146
  @output_stream << @encrypter.data_descriptor(@current_entry.crc, @current_entry.compressed_size, @current_entry.size)
@@ -144,9 +160,9 @@ module Zip
144
160
 
145
161
  def get_compressor(entry, level)
146
162
  case entry.compression_method
147
- when Entry::DEFLATED then
163
+ when Entry::DEFLATED
148
164
  ::Zip::Deflater.new(@output_stream, level, @encrypter)
149
- when Entry::STORED then
165
+ when Entry::STORED
150
166
  ::Zip::PassThruCompressor.new(@output_stream)
151
167
  else
152
168
  raise ::Zip::CompressionMethodError,
@@ -1,8 +1,8 @@
1
1
  module Zip
2
2
  class PassThruCompressor < Compressor #:nodoc:all
3
- def initialize(outputStream)
3
+ def initialize(output_stream)
4
4
  super()
5
- @output_stream = outputStream
5
+ @output_stream = output_stream
6
6
  @crc = Zlib.crc32
7
7
  @size = 0
8
8
  end
@@ -1,38 +1,29 @@
1
1
  module Zip
2
2
  class PassThruDecompressor < Decompressor #:nodoc:all
3
- def initialize(input_stream, chars_to_read)
4
- super(input_stream)
5
- @chars_to_read = chars_to_read
3
+ def initialize(*args)
4
+ super
6
5
  @read_so_far = 0
7
- @has_returned_empty_string = false
8
6
  end
9
7
 
10
- def sysread(number_of_bytes = nil, buf = '')
11
- if input_finished?
12
- has_returned_empty_string_val = @has_returned_empty_string
13
- @has_returned_empty_string = true
14
- return '' unless has_returned_empty_string_val
15
- return
16
- end
8
+ def read(length = nil, outbuf = ''.b)
9
+ return (length.nil? || length.zero? ? '' : nil) if eof
17
10
 
18
- if number_of_bytes.nil? || @read_so_far + number_of_bytes > @chars_to_read
19
- number_of_bytes = @chars_to_read - @read_so_far
11
+ if length.nil? || (@read_so_far + length) > decompressed_size
12
+ length = decompressed_size - @read_so_far
20
13
  end
21
- @read_so_far += number_of_bytes
22
- @input_stream.read(number_of_bytes, buf)
23
- end
24
14
 
25
- def produce_input
26
- sysread(::Zip::Decompressor::CHUNK_SIZE)
15
+ @read_so_far += length
16
+ input_stream.read(length, outbuf)
27
17
  end
28
18
 
29
- def input_finished?
30
- @read_so_far >= @chars_to_read
19
+ def eof
20
+ @read_so_far >= decompressed_size
31
21
  end
32
22
 
33
- alias eof input_finished?
34
- alias eof? input_finished?
23
+ alias eof? eof
35
24
  end
25
+
26
+ ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_STORE, ::Zip::PassThruDecompressor)
36
27
  end
37
28
 
38
29
  # Copyright (C) 2002, 2003 Thomas Sondergaard
@@ -1,11 +1,11 @@
1
1
  module Zip
2
2
  class StreamableDirectory < Entry
3
- def initialize(zipfile, entry, srcPath = nil, permissionInt = nil)
3
+ def initialize(zipfile, entry, src_path = nil, permission = nil)
4
4
  super(zipfile, entry)
5
5
 
6
6
  @ftype = :directory
7
- entry.get_extra_attributes_from_path(srcPath) if srcPath
8
- @unix_perms = permissionInt if permissionInt
7
+ entry.get_extra_attributes_from_path(src_path) if src_path
8
+ @unix_perms = permission if permission
9
9
  end
10
10
  end
11
11
  end
@@ -1,13 +1,8 @@
1
1
  module Zip
2
- class StreamableStream < DelegateClass(Entry) # nodoc:all
2
+ class StreamableStream < DelegateClass(Entry) # :nodoc:all
3
3
  def initialize(entry)
4
4
  super(entry)
5
- dirname = if zipfile.is_a?(::String)
6
- ::File.dirname(zipfile)
7
- else
8
- nil
9
- end
10
- @temp_file = Tempfile.new(::File.basename(name), dirname)
5
+ @temp_file = Tempfile.new(::File.basename(name))
11
6
  @temp_file.binmode
12
7
  end
13
8
 
@@ -27,6 +22,7 @@ module Zip
27
22
  unless @temp_file.closed?
28
23
  raise StandardError, "cannot open entry for reading while its open for writing - #{name}"
29
24
  end
25
+
30
26
  @temp_file.open # reopens tempfile from top
31
27
  @temp_file.binmode
32
28
  if block_given?
@@ -40,9 +36,9 @@ module Zip
40
36
  end
41
37
  end
42
38
 
43
- def write_to_zip_output_stream(aZipOutputStream)
44
- aZipOutputStream.put_next_entry(self)
45
- get_input_stream { |is| ::Zip::IOExtras.copy_stream(aZipOutputStream, is) }
39
+ def write_to_zip_output_stream(output_stream)
40
+ output_stream.put_next_entry(self)
41
+ get_input_stream { |is| ::Zip::IOExtras.copy_stream(output_stream, is) }
46
42
  end
47
43
 
48
44
  def clean_up
data/lib/zip/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Zip
2
- VERSION = '1.3.0'
2
+ VERSION = '2.4.1'
3
3
  end