archive-zip 0.12.0 → 0.13.0.pre1
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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/NEWS.md +5 -0
- data/README.md +1 -1
- data/lib/archive/support/ioextensions.rb +5 -7
- data/lib/archive/support/iowindow.rb +34 -87
- data/lib/archive/support/stringio.rb +27 -0
- data/lib/archive/support/zlib.rb +0 -435
- data/lib/archive/zip/codec/deflate/reader.rb +187 -0
- data/lib/archive/zip/codec/deflate/writer.rb +209 -0
- data/lib/archive/zip/codec/deflate.rb +92 -244
- data/lib/archive/zip/codec/null_encryption.rb +4 -184
- data/lib/archive/zip/codec/store/reader.rb +97 -0
- data/lib/archive/zip/codec/store/writer.rb +78 -0
- data/lib/archive/zip/codec/store.rb +6 -231
- data/lib/archive/zip/codec/traditional_encryption/base.rb +85 -0
- data/lib/archive/zip/codec/traditional_encryption/reader.rb +65 -0
- data/lib/archive/zip/codec/traditional_encryption/writer.rb +71 -0
- data/lib/archive/zip/codec/traditional_encryption.rb +6 -360
- data/lib/archive/zip/dos_time.rb +103 -0
- data/lib/archive/zip/entry.rb +86 -70
- data/lib/archive/zip.rb +2 -5
- metadata +35 -227
- data/.yardopts +0 -1
- data/Rakefile +0 -247
- data/lib/archive/support/binary_stringio.rb +0 -30
- data/lib/archive/support/integer.rb +0 -13
- data/lib/archive/support/io-like.rb +0 -14
- data/lib/archive/support/time.rb +0 -119
- data/lib/archive/zip/version.rb +0 -6
- data/spec/archive/dos_time_spec.rb +0 -113
- data/spec/archive/zip/archive_spec.rb +0 -54
- data/spec/archive/zip/codec/deflate/compress/checksum_spec.rb +0 -44
- data/spec/archive/zip/codec/deflate/compress/close_spec.rb +0 -45
- data/spec/archive/zip/codec/deflate/compress/crc32_spec.rb +0 -23
- data/spec/archive/zip/codec/deflate/compress/data_descriptor_spec.rb +0 -74
- data/spec/archive/zip/codec/deflate/compress/new_spec.rb +0 -39
- data/spec/archive/zip/codec/deflate/compress/open_spec.rb +0 -48
- data/spec/archive/zip/codec/deflate/compress/write_spec.rb +0 -111
- data/spec/archive/zip/codec/deflate/decompress/checksum_spec.rb +0 -20
- data/spec/archive/zip/codec/deflate/decompress/close_spec.rb +0 -34
- data/spec/archive/zip/codec/deflate/decompress/crc32_spec.rb +0 -20
- data/spec/archive/zip/codec/deflate/decompress/data_descriptor_spec.rb +0 -74
- data/spec/archive/zip/codec/deflate/decompress/new_spec.rb +0 -16
- data/spec/archive/zip/codec/deflate/decompress/open_spec.rb +0 -29
- data/spec/archive/zip/codec/deflate/fixtures/classes.rb +0 -25
- data/spec/archive/zip/codec/deflate/fixtures/compressed_file.bin +0 -1
- data/spec/archive/zip/codec/deflate/fixtures/compressed_file_nocomp.bin +0 -0
- data/spec/archive/zip/codec/deflate/fixtures/raw_file.txt +0 -10
- data/spec/archive/zip/codec/null_encryption/decrypt/close_spec.rb +0 -34
- data/spec/archive/zip/codec/null_encryption/decrypt/new_spec.rb +0 -16
- data/spec/archive/zip/codec/null_encryption/decrypt/open_spec.rb +0 -29
- data/spec/archive/zip/codec/null_encryption/decrypt/read_spec.rb +0 -26
- data/spec/archive/zip/codec/null_encryption/decrypt/rewind_spec.rb +0 -27
- data/spec/archive/zip/codec/null_encryption/decrypt/seek_spec.rb +0 -59
- data/spec/archive/zip/codec/null_encryption/decrypt/tell_spec.rb +0 -23
- data/spec/archive/zip/codec/null_encryption/encrypt/close_spec.rb +0 -34
- data/spec/archive/zip/codec/null_encryption/encrypt/new_spec.rb +0 -16
- data/spec/archive/zip/codec/null_encryption/encrypt/open_spec.rb +0 -31
- data/spec/archive/zip/codec/null_encryption/encrypt/rewind_spec.rb +0 -28
- data/spec/archive/zip/codec/null_encryption/encrypt/seek_spec.rb +0 -52
- data/spec/archive/zip/codec/null_encryption/encrypt/tell_spec.rb +0 -31
- data/spec/archive/zip/codec/null_encryption/encrypt/write_spec.rb +0 -31
- data/spec/archive/zip/codec/null_encryption/fixtures/classes.rb +0 -12
- data/spec/archive/zip/codec/null_encryption/fixtures/raw_file.txt +0 -10
- data/spec/archive/zip/codec/store/compress/close_spec.rb +0 -34
- data/spec/archive/zip/codec/store/compress/data_descriptor_spec.rb +0 -77
- data/spec/archive/zip/codec/store/compress/new_spec.rb +0 -16
- data/spec/archive/zip/codec/store/compress/open_spec.rb +0 -29
- data/spec/archive/zip/codec/store/compress/rewind_spec.rb +0 -28
- data/spec/archive/zip/codec/store/compress/seek_spec.rb +0 -52
- data/spec/archive/zip/codec/store/compress/tell_spec.rb +0 -31
- data/spec/archive/zip/codec/store/compress/write_spec.rb +0 -29
- data/spec/archive/zip/codec/store/decompress/close_spec.rb +0 -34
- data/spec/archive/zip/codec/store/decompress/data_descriptor_spec.rb +0 -75
- data/spec/archive/zip/codec/store/decompress/new_spec.rb +0 -16
- data/spec/archive/zip/codec/store/decompress/open_spec.rb +0 -29
- data/spec/archive/zip/codec/store/decompress/read_spec.rb +0 -26
- data/spec/archive/zip/codec/store/decompress/rewind_spec.rb +0 -27
- data/spec/archive/zip/codec/store/decompress/seek_spec.rb +0 -59
- data/spec/archive/zip/codec/store/decompress/tell_spec.rb +0 -23
- data/spec/archive/zip/codec/store/fixtures/classes.rb +0 -12
- data/spec/archive/zip/codec/store/fixtures/raw_file.txt +0 -10
- data/spec/archive/zip/codec/traditional_encryption/decrypt/close_spec.rb +0 -53
- data/spec/archive/zip/codec/traditional_encryption/decrypt/new_spec.rb +0 -20
- data/spec/archive/zip/codec/traditional_encryption/decrypt/open_spec.rb +0 -43
- data/spec/archive/zip/codec/traditional_encryption/decrypt/read_spec.rb +0 -127
- data/spec/archive/zip/codec/traditional_encryption/decrypt/rewind_spec.rb +0 -36
- data/spec/archive/zip/codec/traditional_encryption/decrypt/seek_spec.rb +0 -80
- data/spec/archive/zip/codec/traditional_encryption/decrypt/tell_spec.rb +0 -27
- data/spec/archive/zip/codec/traditional_encryption/encrypt/close_spec.rb +0 -53
- data/spec/archive/zip/codec/traditional_encryption/encrypt/new_spec.rb +0 -20
- data/spec/archive/zip/codec/traditional_encryption/encrypt/open_spec.rb +0 -41
- data/spec/archive/zip/codec/traditional_encryption/encrypt/rewind_spec.rb +0 -39
- data/spec/archive/zip/codec/traditional_encryption/encrypt/seek_spec.rb +0 -73
- data/spec/archive/zip/codec/traditional_encryption/encrypt/tell_spec.rb +0 -40
- data/spec/archive/zip/codec/traditional_encryption/encrypt/write_spec.rb +0 -114
- data/spec/archive/zip/codec/traditional_encryption/fixtures/classes.rb +0 -27
- data/spec/archive/zip/codec/traditional_encryption/fixtures/encrypted_file.bin +0 -0
- data/spec/archive/zip/codec/traditional_encryption/fixtures/raw_file.txt +0 -10
- data/spec/binary_stringio/new_spec.rb +0 -40
- data/spec/binary_stringio/set_encoding_spec.rb +0 -17
- data/spec/ioextensions/read_exactly_spec.rb +0 -52
- data/spec/zlib/fixtures/classes.rb +0 -65
- data/spec/zlib/fixtures/compressed_file.bin +0 -1
- data/spec/zlib/fixtures/compressed_file_gzip.bin +0 -0
- data/spec/zlib/fixtures/compressed_file_huffman.bin +0 -2
- data/spec/zlib/fixtures/compressed_file_minmem.bin +0 -0
- data/spec/zlib/fixtures/compressed_file_minwin.bin +0 -1
- data/spec/zlib/fixtures/compressed_file_nocomp.bin +0 -0
- data/spec/zlib/fixtures/compressed_file_raw.bin +0 -1
- data/spec/zlib/fixtures/raw_file.txt +0 -10
- data/spec/zlib/zreader/checksum_spec.rb +0 -42
- data/spec/zlib/zreader/close_spec.rb +0 -16
- data/spec/zlib/zreader/compressed_size_spec.rb +0 -20
- data/spec/zlib/zreader/new_spec.rb +0 -43
- data/spec/zlib/zreader/open_spec.rb +0 -51
- data/spec/zlib/zreader/read_spec.rb +0 -58
- data/spec/zlib/zreader/rewind_spec.rb +0 -25
- data/spec/zlib/zreader/seek_spec.rb +0 -57
- data/spec/zlib/zreader/tell_spec.rb +0 -23
- data/spec/zlib/zreader/uncompressed_size_spec.rb +0 -20
- data/spec/zlib/zwriter/checksum_spec.rb +0 -43
- data/spec/zlib/zwriter/close_spec.rb +0 -16
- data/spec/zlib/zwriter/compressed_size_spec.rb +0 -21
- data/spec/zlib/zwriter/new_spec.rb +0 -66
- data/spec/zlib/zwriter/open_spec.rb +0 -70
- data/spec/zlib/zwriter/rewind_spec.rb +0 -28
- data/spec/zlib/zwriter/seek_spec.rb +0 -52
- data/spec/zlib/zwriter/tell_spec.rb +0 -31
- data/spec/zlib/zwriter/uncompressed_size_spec.rb +0 -21
- data/spec/zlib/zwriter/write_spec.rb +0 -28
data/lib/archive/support/zlib.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'zlib'
|
4
4
|
|
5
|
-
require 'archive/support/io-like'
|
6
|
-
|
7
5
|
module Zlib # :nodoc:
|
8
6
|
# The maximum size of the zlib history buffer. Note that zlib allows larger
|
9
7
|
# values to enable different inflate modes. See Zlib::Inflate.new for details.
|
@@ -19,437 +17,4 @@ module Zlib # :nodoc:
|
|
19
17
|
# simpler decoder to be used to inflate. Provided here only for Ruby versions
|
20
18
|
# that do not provide it.
|
21
19
|
FIXED = 4 unless const_defined?(:FIXED)
|
22
|
-
|
23
|
-
# Zlib::ZWriter is a writable, IO-like object (includes IO::Like) which wraps
|
24
|
-
# other writable, IO-like objects in order to facilitate writing data to those
|
25
|
-
# objects using the deflate method of compression.
|
26
|
-
class ZWriter
|
27
|
-
include IO::Like
|
28
|
-
|
29
|
-
# Creates a new instance of this class with the given arguments using #new
|
30
|
-
# and then passes the instance to the given block. The #close method is
|
31
|
-
# guaranteed to be called after the block completes.
|
32
|
-
#
|
33
|
-
# Equivalent to #new if no block is given.
|
34
|
-
def self.open(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil)
|
35
|
-
zw = new(delegate, level, window_bits, mem_level, strategy)
|
36
|
-
return zw unless block_given?
|
37
|
-
|
38
|
-
begin
|
39
|
-
yield(zw)
|
40
|
-
ensure
|
41
|
-
zw.close unless zw.closed?
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Creates a new instance of this class. _delegate_ must respond to the
|
46
|
-
# _write_ method as an instance of IO would. _level_, _window_bits_,
|
47
|
-
# _mem_level_, and _strategy_ are all passed directly to
|
48
|
-
# Zlib::Deflate.new().
|
49
|
-
#
|
50
|
-
# <b>
|
51
|
-
# The following descriptions of _level_, _window_bits_, _mem_level_, and
|
52
|
-
# _strategy_ are based upon or pulled largely verbatim from descriptions
|
53
|
-
# found in zlib.h version 1.2.3 with changes made to account for different
|
54
|
-
# parameter names and to improve readability. Some of the statements
|
55
|
-
# concerning default settings or value ranges may not be accurate depending
|
56
|
-
# on the version of the zlib library used by a given Ruby interpreter.
|
57
|
-
# </b>
|
58
|
-
#
|
59
|
-
# The _level_ parameter must be +nil+, Zlib::DEFAULT_COMPRESSION, or between
|
60
|
-
# <tt>0</tt> and <tt>9</tt>: <tt>1</tt> gives best speed, <tt>9</tt> gives
|
61
|
-
# best compression, <tt>0</tt> gives no compression at all (the input data
|
62
|
-
# is simply copied a block at a time). Zlib::DEFAULT_COMPRESSION requests a
|
63
|
-
# default compromise between speed and compression (currently equivalent to
|
64
|
-
# level <tt>6</tt>). If unspecified or +nil+, _level_ defaults to
|
65
|
-
# Zlib::DEFAULT_COMPRESSION.
|
66
|
-
#
|
67
|
-
# The _window_bits_ parameter specifies the size of the history buffer, the
|
68
|
-
# format of the compressed stream, and the kind of checksum returned by the
|
69
|
-
# checksum method. The size of the history buffer is specified by setting
|
70
|
-
# the value of _window_bits_ in the range of <tt>8</tt>..<tt>15</tt>,
|
71
|
-
# inclusive. A value of <tt>8</tt> indicates a small window which reduces
|
72
|
-
# memory usage but lowers the compression ratio while a value of <tt>15</tt>
|
73
|
-
# indicates a larger window which increases memory usage but raises the
|
74
|
-
# compression ratio. Modification of this base value for _window_bits_ as
|
75
|
-
# noted below dictates what kind of compressed stream and checksum will be
|
76
|
-
# produced <b>while preserving the setting for the history buffer</b>.
|
77
|
-
#
|
78
|
-
# If nothing else is done to the base value of _window_bits_, a zlib stream
|
79
|
-
# is to be produced with an appropriate header and trailer. In this case
|
80
|
-
# the checksum method of this object will be an adler32.
|
81
|
-
#
|
82
|
-
# Adding <tt>16</tt> to the base value of _window_bits_ indicates that a
|
83
|
-
# gzip stream is to be produced with an appropriate header and trailer. The
|
84
|
-
# gzip header will have no file name, no extra data, no comment, no
|
85
|
-
# modification time (set to zero), no header crc, and the operating system
|
86
|
-
# will be set to <tt>255</tt> (unknown). In this case the checksum
|
87
|
-
# attribute of this object will be a crc32.
|
88
|
-
#
|
89
|
-
# Finally, negating the base value of _window_bits_ indicates that a raw
|
90
|
-
# zlib stream is to be produced without any header or trailer. In this case
|
91
|
-
# the checksum method of this object will always return <tt>nil</tt>. This is
|
92
|
-
# for use with other formats that use the deflate compressed data format
|
93
|
-
# such as zip. Such formats should provide their own check values.
|
94
|
-
#
|
95
|
-
# If unspecified or +nil+, _window_bits_ defaults to <tt>15</tt>.
|
96
|
-
#
|
97
|
-
# The _mem_level_ parameter specifies how much memory should be allocated
|
98
|
-
# for the internal compression state. A value of <tt>1</tt> uses minimum
|
99
|
-
# memory but is slow and reduces compression ratio; a value of <tt>9</tt>
|
100
|
-
# uses maximum memory for optimal speed. The default value is <tt>8</tt> if
|
101
|
-
# unspecified or +nil+.
|
102
|
-
#
|
103
|
-
# The _strategy_ parameter is used to tune the compression algorithm. It
|
104
|
-
# only affects the compression ratio but not the correctness of the
|
105
|
-
# compressed output even if it is not set appropriately. The default value
|
106
|
-
# is Zlib::DEFAULT_STRATEGY if unspecified or +nil+.
|
107
|
-
#
|
108
|
-
# Use the value Zlib::DEFAULT_STRATEGY for normal data, Zlib::FILTERED for
|
109
|
-
# data produced by a filter (or predictor), Zlib::HUFFMAN_ONLY to force
|
110
|
-
# Huffman encoding only (no string match), Zlib::RLE to limit match
|
111
|
-
# distances to 1 (run-length encoding), or Zlib::FIXED to simplify decoder
|
112
|
-
# requirements.
|
113
|
-
#
|
114
|
-
# The effect of Zlib::FILTERED is to force more Huffman coding and less
|
115
|
-
# string matching; it is somewhat intermediate between
|
116
|
-
# Zlib::DEFAULT_STRATEGY and Zlib::HUFFMAN_ONLY. Filtered data consists
|
117
|
-
# mostly of small values with a somewhat random distribution. In this case,
|
118
|
-
# the compression algorithm is tuned to compress them better.
|
119
|
-
#
|
120
|
-
# Zlib::RLE is designed to be almost as fast as Zlib::HUFFMAN_ONLY, but give
|
121
|
-
# better compression for PNG image data.
|
122
|
-
#
|
123
|
-
# Zlib::FIXED prevents the use of dynamic Huffman codes, allowing for a
|
124
|
-
# simpler decoder for special applications.
|
125
|
-
#
|
126
|
-
# This class has extremely limited seek capabilities. It is possible to
|
127
|
-
# seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
|
128
|
-
# As a result, the _pos_ and _tell_ methods also work as expected.
|
129
|
-
#
|
130
|
-
# If _delegate_ also responds to _rewind_, then the _rewind_ method of this
|
131
|
-
# class can be used to reset the whole stream back to the beginning. Using
|
132
|
-
# _seek_ of this class to seek directly to offset <tt>0</tt> using
|
133
|
-
# <tt>IO::SEEK_SET</tt> for whence will also work in this case.
|
134
|
-
#
|
135
|
-
# <b>NOTE:</b> Due to limitations in Ruby's finalization capabilities, the
|
136
|
-
# #close method is _not_ automatically called when this object is garbage
|
137
|
-
# collected. Make sure to call #close when finished with this object.
|
138
|
-
def initialize(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil)
|
139
|
-
@delegate = delegate
|
140
|
-
@level = level
|
141
|
-
@window_bits = window_bits
|
142
|
-
@mem_level = mem_level
|
143
|
-
@strategy = strategy
|
144
|
-
@deflater = Zlib::Deflate.new(@level, @window_bits, @mem_level, @strategy)
|
145
|
-
@deflate_buffer = ''
|
146
|
-
@checksum = nil
|
147
|
-
@compressed_size = nil
|
148
|
-
@uncompressed_size = nil
|
149
|
-
end
|
150
|
-
|
151
|
-
protected
|
152
|
-
|
153
|
-
# The delegate object to which compressed data is written.
|
154
|
-
attr_reader :delegate
|
155
|
-
|
156
|
-
public
|
157
|
-
|
158
|
-
# Returns the checksum computed over the data written to this stream so far.
|
159
|
-
#
|
160
|
-
# <b>NOTE:</b> Refer to the documentation of #new concerning _window_bits_
|
161
|
-
# to learn what kind of checksum will be returned.
|
162
|
-
#
|
163
|
-
# <b>NOTE:</b> Anything still in the internal write buffer has not been
|
164
|
-
# processed, so calling #flush prior to calling this method may be necessary
|
165
|
-
# for an accurate checksum.
|
166
|
-
def checksum
|
167
|
-
return nil if @window_bits < 0
|
168
|
-
@deflater.closed? ? @checksum : @deflater.adler
|
169
|
-
end
|
170
|
-
|
171
|
-
# Closes the writer by finishing the compressed data and flushing it to the
|
172
|
-
# delegate.
|
173
|
-
#
|
174
|
-
# Raises IOError if called more than once.
|
175
|
-
def close
|
176
|
-
flush()
|
177
|
-
@deflate_buffer << @deflater.finish unless @deflater.finished?
|
178
|
-
begin
|
179
|
-
until @deflate_buffer.empty? do
|
180
|
-
@deflate_buffer.slice!(0, delegate.write(@deflate_buffer))
|
181
|
-
end
|
182
|
-
rescue Errno::EAGAIN, Errno::EINTR
|
183
|
-
retry if write_ready?
|
184
|
-
end
|
185
|
-
@checksum = @deflater.adler
|
186
|
-
@compressed_size = @deflater.total_out
|
187
|
-
@uncompressed_size = @deflater.total_in
|
188
|
-
@deflater.close
|
189
|
-
super()
|
190
|
-
nil
|
191
|
-
end
|
192
|
-
|
193
|
-
# Returns the number of bytes of compressed data produced so far.
|
194
|
-
#
|
195
|
-
# <b>NOTE:</b> This value is only updated when both the internal write
|
196
|
-
# buffer is flushed and there is enough data to produce a compressed block.
|
197
|
-
# It does not necessarily reflect the amount of data written to the
|
198
|
-
# delegate until this stream is closed however. Until then the only
|
199
|
-
# guarantee is that the value will be greater than or equal to <tt>0</tt>.
|
200
|
-
def compressed_size
|
201
|
-
@deflater.closed? ? @compressed_size : @deflater.total_out
|
202
|
-
end
|
203
|
-
|
204
|
-
# Returns the number of bytes sent to be compressed so far.
|
205
|
-
#
|
206
|
-
# <b>NOTE:</b> This value is only updated when the internal write buffer is
|
207
|
-
# flushed.
|
208
|
-
def uncompressed_size
|
209
|
-
@deflater.closed? ? @uncompressed_size : @deflater.total_in
|
210
|
-
end
|
211
|
-
|
212
|
-
private
|
213
|
-
|
214
|
-
# Allows resetting this object and the delegate object back to the beginning
|
215
|
-
# of the stream or reporting the current position in the stream.
|
216
|
-
#
|
217
|
-
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is either
|
218
|
-
# IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_ is
|
219
|
-
# IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
220
|
-
# method.
|
221
|
-
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
222
|
-
unless offset == 0 &&
|
223
|
-
((whence == IO::SEEK_SET && delegate.respond_to?(:rewind)) ||
|
224
|
-
whence == IO::SEEK_CUR) then
|
225
|
-
raise Errno::EINVAL
|
226
|
-
end
|
227
|
-
|
228
|
-
case whence
|
229
|
-
when IO::SEEK_SET
|
230
|
-
delegate.rewind
|
231
|
-
@deflater.finish
|
232
|
-
@deflater.close
|
233
|
-
@deflater = Zlib::Deflate.new(
|
234
|
-
@level, @window_bits, @mem_level, @strategy
|
235
|
-
)
|
236
|
-
@deflate_buffer = ''
|
237
|
-
0
|
238
|
-
when IO::SEEK_CUR
|
239
|
-
@deflater.total_in
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
def unbuffered_write(string)
|
244
|
-
# First try to write out the contents of the deflate buffer because if
|
245
|
-
# that raises a failure we can let that pass up the call stack without
|
246
|
-
# having polluted the deflater instance.
|
247
|
-
until @deflate_buffer.empty? do
|
248
|
-
@deflate_buffer.slice!(0, delegate.write(@deflate_buffer))
|
249
|
-
end
|
250
|
-
# At this point we can deflate the given string into a new buffer and
|
251
|
-
# behave as if it was written.
|
252
|
-
@deflate_buffer = @deflater.deflate(string)
|
253
|
-
string.length
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
# Zlib::ZReader is a readable, IO-like object (includes IO::Like) which wraps
|
258
|
-
# other readable, IO-like objects in order to facilitate reading data from
|
259
|
-
# those objects using the inflate method of decompression.
|
260
|
-
class ZReader
|
261
|
-
include IO::Like
|
262
|
-
|
263
|
-
# The number of bytes to read from the delegate object each time the
|
264
|
-
# internal read buffer is filled.
|
265
|
-
DEFAULT_DELEGATE_READ_SIZE = 4096
|
266
|
-
|
267
|
-
# Creates a new instance of this class with the given arguments using #new
|
268
|
-
# and then passes the instance to the given block. The #close method is
|
269
|
-
# guaranteed to be called after the block completes.
|
270
|
-
#
|
271
|
-
# Equivalent to #new if no block is given.
|
272
|
-
def self.open(delegate, window_bits = nil)
|
273
|
-
zr = new(delegate, window_bits)
|
274
|
-
return zr unless block_given?
|
275
|
-
|
276
|
-
begin
|
277
|
-
yield(zr)
|
278
|
-
ensure
|
279
|
-
zr.close unless zr.closed?
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
# Creates a new instance of this class. _delegate_ must respond to the
|
284
|
-
# _read_ method as an IO instance would. _window_bits_ is passed directly
|
285
|
-
# to Zlib::Inflate.new().
|
286
|
-
#
|
287
|
-
# <b>
|
288
|
-
# The following description of _window_bits_ is based on the description
|
289
|
-
# found in zlib.h version 1.2.3. Some of the statements concerning default
|
290
|
-
# settings or value ranges may not be accurate depending on the version of
|
291
|
-
# the zlib library used by a given Ruby interpreter.
|
292
|
-
# </b>
|
293
|
-
#
|
294
|
-
# The _window_bits_ parameter specifies the size of the history buffer, the
|
295
|
-
# format of the compressed stream, and the kind of checksum returned by the
|
296
|
-
# checksum method. The size of the history buffer is specified by setting
|
297
|
-
# the value of _window_bits_ in the range of <tt>8</tt>..<tt>15</tt>,
|
298
|
-
# inclusive. It must be at least as large as the setting used to create the
|
299
|
-
# stream or a Zlib::DataError will be raised. Modification of this base
|
300
|
-
# value for _window_bits_ as noted below dictates what kind of compressed
|
301
|
-
# stream is expected and what kind of checksum will be produced <b>while
|
302
|
-
# preserving the setting for the history buffer</b>.
|
303
|
-
#
|
304
|
-
# If nothing else is done to the base value of _window_bits_, a zlib stream
|
305
|
-
# is expected with an appropriate header and trailer. In this case the
|
306
|
-
# checksum method of this object will be an adler32.
|
307
|
-
#
|
308
|
-
# Adding <tt>16</tt> to the base value of _window_bits_ indicates that a
|
309
|
-
# gzip stream is expected with an appropriate header and trailer. In this
|
310
|
-
# case the checksum method of this object will be a crc32.
|
311
|
-
#
|
312
|
-
# Adding <tt>32</tt> to the base value of _window_bits_ indicates that an
|
313
|
-
# automatic detection of the stream format should be made based on the
|
314
|
-
# header in the stream. In this case the checksum method of this object
|
315
|
-
# will depend on whether a zlib or a gzip stream is detected.
|
316
|
-
#
|
317
|
-
# Finally, negating the base value of _window_bits_ indicates that a raw
|
318
|
-
# zlib stream is expected without any header or trailer. In this case the
|
319
|
-
# checksum method of this object will always return <tt>nil</tt>. This is for
|
320
|
-
# use with other formats that use the deflate compressed data format such as
|
321
|
-
# zip. Such formats should provide their own check values.
|
322
|
-
#
|
323
|
-
# If unspecified or +nil+, _window_bits_ defaults to <tt>15</tt>.
|
324
|
-
#
|
325
|
-
# In all cases, Zlib::DataError is raised if the wrong stream format is
|
326
|
-
# found <b>when reading</b>.
|
327
|
-
#
|
328
|
-
# This class has extremely limited seek capabilities. It is possible to
|
329
|
-
# seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
|
330
|
-
# As a result, the _pos_ and _tell_ methods also work as expected.
|
331
|
-
#
|
332
|
-
# Due to certain optimizations within IO::Like#seek and if there is data in
|
333
|
-
# the read buffer, the _seek_ method can be used to seek forward from the
|
334
|
-
# current stream position up to the end of the buffer. Unless it is known
|
335
|
-
# definitively how much data is in the buffer, it is best to avoid relying
|
336
|
-
# on this behavior.
|
337
|
-
#
|
338
|
-
# If _delegate_ also responds to _rewind_, then the _rewind_ method of this
|
339
|
-
# class can be used to reset the whole stream back to the beginning. Using
|
340
|
-
# _seek_ of this class to seek directly to offset <tt>0</tt> using
|
341
|
-
# <tt>IO::SEEK_SET</tt> for whence will also work in this case.
|
342
|
-
#
|
343
|
-
# Any other seeking attempts, will raise Errno::EINVAL exceptions.
|
344
|
-
#
|
345
|
-
# <b>NOTE:</b> Due to limitations in Ruby's finalization capabilities, the
|
346
|
-
# #close method is _not_ automatically called when this object is garbage
|
347
|
-
# collected. Make sure to call #close when finished with this object.
|
348
|
-
def initialize(delegate, window_bits = nil)
|
349
|
-
@delegate = delegate
|
350
|
-
@delegate_read_size = DEFAULT_DELEGATE_READ_SIZE
|
351
|
-
@window_bits = window_bits
|
352
|
-
@inflater = Zlib::Inflate.new(@window_bits)
|
353
|
-
@inflate_buffer = ''
|
354
|
-
@checksum = nil
|
355
|
-
@compressed_size = nil
|
356
|
-
@uncompressed_size = nil
|
357
|
-
end
|
358
|
-
|
359
|
-
# The number of bytes to read from the delegate object each time the
|
360
|
-
# internal read buffer is filled.
|
361
|
-
attr_accessor :delegate_read_size
|
362
|
-
|
363
|
-
protected
|
364
|
-
|
365
|
-
# The delegate object from which compressed data is read.
|
366
|
-
attr_reader :delegate
|
367
|
-
|
368
|
-
public
|
369
|
-
|
370
|
-
# Returns the checksum computed over the data read from this stream.
|
371
|
-
#
|
372
|
-
# <b>NOTE:</b> Refer to the documentation of #new concerning _window_bits_
|
373
|
-
# to learn what kind of checksum will be returned.
|
374
|
-
#
|
375
|
-
# <b>NOTE:</b> The contents of the internal read buffer are immediately
|
376
|
-
# processed any time the internal buffer is filled, so this checksum is only
|
377
|
-
# accurate if all data has been read out of this object.
|
378
|
-
def checksum
|
379
|
-
return nil if @window_bits < 0
|
380
|
-
@inflater.closed? ? @checksum : @inflater.adler
|
381
|
-
end
|
382
|
-
|
383
|
-
# Closes the reader.
|
384
|
-
#
|
385
|
-
# Raises IOError if called more than once.
|
386
|
-
def close
|
387
|
-
super()
|
388
|
-
@checksum = @inflater.adler
|
389
|
-
@compressed_size = @inflater.total_in
|
390
|
-
@uncompressed_size = @inflater.total_out
|
391
|
-
@inflater.close
|
392
|
-
nil
|
393
|
-
end
|
394
|
-
|
395
|
-
# Returns the number of bytes sent to be compressed so far.
|
396
|
-
#
|
397
|
-
# <b>NOTE:</b> This value is updated whenever the internal read buffer needs
|
398
|
-
# to be filled, not when data is read out of this stream.
|
399
|
-
def compressed_size
|
400
|
-
@inflater.closed? ? @compressed_size : @inflater.total_in
|
401
|
-
end
|
402
|
-
|
403
|
-
# Returns the number of bytes of decompressed data produced so far.
|
404
|
-
#
|
405
|
-
# <b>NOTE:</b> This value is updated whenever the internal read buffer needs
|
406
|
-
# to be filled, not when data is read out of this stream.
|
407
|
-
def uncompressed_size
|
408
|
-
@inflater.closed? ? @uncompressed_size : @inflater.total_out
|
409
|
-
end
|
410
|
-
|
411
|
-
private
|
412
|
-
|
413
|
-
def unbuffered_read(length)
|
414
|
-
if @inflate_buffer.empty? && @inflater.finished? then
|
415
|
-
raise EOFError, 'end of file reached'
|
416
|
-
end
|
417
|
-
|
418
|
-
begin
|
419
|
-
while @inflate_buffer.length < length && ! @inflater.finished? do
|
420
|
-
@inflate_buffer <<
|
421
|
-
@inflater.inflate(delegate.read(@delegate_read_size))
|
422
|
-
end
|
423
|
-
rescue Errno::EINTR, Errno::EAGAIN
|
424
|
-
raise if @inflate_buffer.empty?
|
425
|
-
end
|
426
|
-
@inflate_buffer.slice!(0, length)
|
427
|
-
end
|
428
|
-
|
429
|
-
# Allows resetting this object and the delegate object back to the beginning
|
430
|
-
# of the stream or reporting the current position in the stream.
|
431
|
-
#
|
432
|
-
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is either
|
433
|
-
# IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_ is
|
434
|
-
# IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
435
|
-
# method.
|
436
|
-
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
437
|
-
unless offset == 0 &&
|
438
|
-
((whence == IO::SEEK_SET && delegate.respond_to?(:rewind)) ||
|
439
|
-
whence == IO::SEEK_CUR) then
|
440
|
-
raise Errno::EINVAL
|
441
|
-
end
|
442
|
-
|
443
|
-
case whence
|
444
|
-
when IO::SEEK_SET
|
445
|
-
delegate.rewind
|
446
|
-
@inflater.close
|
447
|
-
@inflater = Zlib::Inflate.new(@window_bits)
|
448
|
-
@inflate_buffer = ''
|
449
|
-
0
|
450
|
-
when IO::SEEK_CUR
|
451
|
-
@inflater.total_out - @inflate_buffer.length
|
452
|
-
end
|
453
|
-
end
|
454
|
-
end
|
455
20
|
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'io/like_helpers/delegated_io'
|
4
|
+
|
5
|
+
require 'archive/support/zlib'
|
6
|
+
require 'archive/zip/data_descriptor'
|
7
|
+
|
8
|
+
module Archive; class Zip; module Codec; class Deflate
|
9
|
+
# Archive::Zip::Codec::Deflate::Reader extends Zlib::ZReader in order to
|
10
|
+
# specify the standard Zlib options required by ZIP archives and to provide
|
11
|
+
# a close method which can optionally close the delegate IO-like object.
|
12
|
+
# In addition a convenience method is provided for generating DataDescriptor
|
13
|
+
# objects based on the data which is passed through this object.
|
14
|
+
#
|
15
|
+
# Instances of this class should only be accessed via the
|
16
|
+
# Archive::Zip::Codec::Deflate#decompressor method.
|
17
|
+
class Reader < IO::LikeHelpers::DelegatedIO
|
18
|
+
# The number of bytes to read from the delegate object each time the
|
19
|
+
# internal read buffer is filled.
|
20
|
+
DEFAULT_DELEGATE_READ_SIZE = 8192
|
21
|
+
|
22
|
+
# Creates a new instance of this class. _delegate_ must respond to the
|
23
|
+
# _read_ method as an IO instance would.
|
24
|
+
#
|
25
|
+
# In all cases, Zlib::DataError is raised if the wrong stream format is
|
26
|
+
# found <b>when reading</b>.
|
27
|
+
#
|
28
|
+
# This class has extremely limited seek capabilities. It is possible to
|
29
|
+
# seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
|
30
|
+
# As a result, the _pos_ and _tell_ methods also work as expected.
|
31
|
+
#
|
32
|
+
# Due to certain optimizations within IO::Like#seek and if there is data in
|
33
|
+
# the read buffer, the _seek_ method can be used to seek forward from the
|
34
|
+
# current stream position up to the end of the buffer. Unless it is known
|
35
|
+
# definitively how much data is in the buffer, it is best to avoid relying
|
36
|
+
# on this behavior.
|
37
|
+
#
|
38
|
+
# If _delegate_ also responds to _rewind_, then the _rewind_ method of this
|
39
|
+
# class can be used to reset the whole stream back to the beginning. Using
|
40
|
+
# _seek_ of this class to seek directly to offset <tt>0</tt> using
|
41
|
+
# <tt>IO::SEEK_SET</tt> for whence will also work in this case.
|
42
|
+
#
|
43
|
+
# Any other seeking attempts, will raise Errno::EINVAL exceptions.
|
44
|
+
#
|
45
|
+
# <b>NOTE:</b> Due to limitations in Ruby's finalization capabilities, the
|
46
|
+
# #close method is _not_ automatically called when this object is garbage
|
47
|
+
# collected. Make sure to call #close when finished with this object.
|
48
|
+
def initialize(
|
49
|
+
delegate,
|
50
|
+
autoclose: true,
|
51
|
+
delegate_read_size: DEFAULT_DELEGATE_READ_SIZE
|
52
|
+
)
|
53
|
+
super(delegate, autoclose: autoclose)
|
54
|
+
|
55
|
+
@delegate_read_size = delegate_read_size
|
56
|
+
@read_buffer = "\0".b * @delegate_read_size
|
57
|
+
@inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
58
|
+
@inflate_buffer = ''
|
59
|
+
@inflate_buffer_idx = 0
|
60
|
+
@compressed_size = nil
|
61
|
+
@uncompressed_size = nil
|
62
|
+
@crc32 = 0
|
63
|
+
end
|
64
|
+
|
65
|
+
# The number of bytes to read from the delegate object each time the
|
66
|
+
# internal read buffer is filled.
|
67
|
+
attr_accessor :delegate_read_size
|
68
|
+
|
69
|
+
# Closes the reader.
|
70
|
+
#
|
71
|
+
# Raises IOError if called more than once.
|
72
|
+
def close
|
73
|
+
return nil if closed?
|
74
|
+
|
75
|
+
result = super
|
76
|
+
return result if Symbol === result
|
77
|
+
|
78
|
+
@compressed_size = @inflater.total_in
|
79
|
+
@uncompressed_size = @inflater.total_out
|
80
|
+
@inflate_buffer = nil
|
81
|
+
@inflate_buffer_idx = 0
|
82
|
+
|
83
|
+
# Avoid warnings by only attempting to close the inflater if it was
|
84
|
+
# correctly finished.
|
85
|
+
@inflater.close if @inflater.finished?
|
86
|
+
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# The CRC32 checksum of the uncompressed data read using this object.
|
91
|
+
#
|
92
|
+
# <b>NOTE:</b> The contents of the internal read buffer are immediately
|
93
|
+
# processed any time the internal buffer is filled, so this checksum is
|
94
|
+
# only accurate if all data has been read out of this object.
|
95
|
+
attr_reader :crc32
|
96
|
+
|
97
|
+
# Returns the number of bytes sent to be compressed so far.
|
98
|
+
#
|
99
|
+
# <b>NOTE:</b> This value is updated whenever the internal read buffer needs
|
100
|
+
# to be filled, not when data is read out of this stream.
|
101
|
+
def compressed_size
|
102
|
+
@inflater.closed? ? @compressed_size : @inflater.total_in
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns the number of bytes of decompressed data produced so far.
|
106
|
+
#
|
107
|
+
# <b>NOTE:</b> This value is updated whenever the internal read buffer needs
|
108
|
+
# to be filled, not when data is read out of this stream.
|
109
|
+
def uncompressed_size
|
110
|
+
@inflater.closed? ? @uncompressed_size : @inflater.total_out
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns an instance of Archive::Zip::DataDescriptor with information
|
114
|
+
# regarding the data which has passed through this object from the
|
115
|
+
# delegate object. It is recommended to call the close method before
|
116
|
+
# calling this in order to ensure that no further read operations change
|
117
|
+
# the state of this object.
|
118
|
+
def data_descriptor
|
119
|
+
DataDescriptor.new(crc32, compressed_size, uncompressed_size)
|
120
|
+
end
|
121
|
+
|
122
|
+
def read(length, buffer: nil, buffer_offset: 0)
|
123
|
+
length = Integer(length)
|
124
|
+
raise ArgumentError, 'length must be at least 0' if length < 0
|
125
|
+
if ! buffer.nil?
|
126
|
+
if buffer_offset < 0 || buffer_offset >= buffer.bytesize
|
127
|
+
raise ArgumentError, 'buffer_offset is not a valid buffer index'
|
128
|
+
end
|
129
|
+
if buffer.bytesize - buffer_offset < length
|
130
|
+
raise ArgumentError, 'length is greater than available buffer space'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
assert_readable
|
135
|
+
|
136
|
+
if @inflate_buffer_idx >= @inflate_buffer.size
|
137
|
+
raise EOFError, 'end of file reached' if @inflater.finished?
|
138
|
+
|
139
|
+
@inflate_buffer =
|
140
|
+
begin
|
141
|
+
result = super(@delegate_read_size, buffer: @read_buffer)
|
142
|
+
return result if Symbol === result
|
143
|
+
@inflater.inflate(@read_buffer[0, result])
|
144
|
+
rescue EOFError
|
145
|
+
@inflater.inflate(nil)
|
146
|
+
end
|
147
|
+
@inflate_buffer_idx = 0
|
148
|
+
end
|
149
|
+
|
150
|
+
available = @inflate_buffer.size - @inflate_buffer_idx
|
151
|
+
length = available if available < length
|
152
|
+
content = @inflate_buffer[@inflate_buffer_idx, length]
|
153
|
+
@inflate_buffer_idx += length
|
154
|
+
@crc32 = Zlib.crc32(content, @crc32)
|
155
|
+
return content if buffer.nil?
|
156
|
+
|
157
|
+
buffer[buffer_offset, length] = content
|
158
|
+
return length
|
159
|
+
end
|
160
|
+
|
161
|
+
# Allows resetting this object and the delegate object back to the beginning
|
162
|
+
# of the stream or reporting the current position in the stream.
|
163
|
+
#
|
164
|
+
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is either
|
165
|
+
# IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_ is
|
166
|
+
# IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
167
|
+
# method.
|
168
|
+
def seek(amount, whence = IO::SEEK_SET)
|
169
|
+
assert_open
|
170
|
+
raise Errno::ESPIPE if amount != 0 || whence == IO::SEEK_END
|
171
|
+
|
172
|
+
case whence
|
173
|
+
when IO::SEEK_SET
|
174
|
+
result = super
|
175
|
+
return result if Symbol === result
|
176
|
+
@inflater.reset
|
177
|
+
@inflate_buffer_idx = @inflate_buffer.size
|
178
|
+
@crc32 = 0
|
179
|
+
result
|
180
|
+
when IO::SEEK_CUR
|
181
|
+
@inflater.total_out - (@inflate_buffer.size - @inflate_buffer_idx)
|
182
|
+
else
|
183
|
+
raise Errno::EINVAL
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end; end; end; end
|