Class: Zlib::ZReader
- Inherits:
-
Object
- Object
- Zlib::ZReader
- Includes:
- IO::Like
- Defined in:
- lib/archive/support/zlib.rb
Overview
Zlib::ZReader is a readable, IO-like object (includes IO::Like) which wraps other readable, IO-like objects in order to facilitate reading data from those objects using the inflate method of decompression.
Direct Known Subclasses
Constant Summary collapse
- DEFAULT_DELEGATE_READ_SIZE =
The number of bytes to read from the delegate object each time the internal read buffer is filled.
4096
Instance Attribute Summary collapse
-
#delegate ⇒ Object
readonly
protected
The delegate object from which compressed data is read.
-
#delegate_read_size ⇒ Object
The number of bytes to read from the delegate object each time the internal read buffer is filled.
Class Method Summary collapse
-
.open(delegate, window_bits = nil) ⇒ Object
Creates a new instance of this class with the given arguments using #new and then passes the instance to the given block.
Instance Method Summary collapse
-
#checksum ⇒ Object
Returns the checksum computed over the data read from this stream.
-
#close ⇒ Object
Closes the reader.
-
#compressed_size ⇒ Object
Returns the number of bytes sent to be compressed so far.
-
#initialize(delegate, window_bits = nil) ⇒ ZReader
constructor
Creates a new instance of this class.
- #unbuffered_read(length) ⇒ Object private
-
#unbuffered_seek(offset, whence = IO::SEEK_SET) ⇒ Object
private
Allows resetting this object and the delegate object back to the beginning of the stream or reporting the current position in the stream.
-
#uncompressed_size ⇒ Object
Returns the number of bytes of decompressed data produced so far.
Constructor Details
#initialize(delegate, window_bits = nil) ⇒ ZReader
Creates a new instance of this class. delegate must respond to the read method as an IO instance would. window_bits is passed directly to Zlib::Inflate.new().
The following description of window_bits is based on the description found in zlib.h version 1.2.3. Some of the statements concerning default settings or value ranges may not be accurate depending on the version of the zlib library used by a given Ruby interpreter.
The window_bits parameter specifies the size of the history buffer, the format of the compressed stream, and the kind of checksum returned by the checksum method. The size of the history buffer is specified by setting the value of window_bits in the range of 8
..15
, inclusive. It must be at least as large as the setting used to create the stream or a Zlib::DataError will be raised. Modification of this base value for window_bits as noted below dictates what kind of compressed stream is expected and what kind of checksum will be produced while preserving the setting for the history buffer.
If nothing else is done to the base value of window_bits, a zlib stream is expected with an appropriate header and trailer. In this case the checksum method of this object will be an adler32.
Adding 16
to the base value of window_bits indicates that a gzip stream is expected with an appropriate header and trailer. In this case the checksum method of this object will be a crc32.
Adding 32
to the base value of window_bits indicates that an automatic detection of the stream format should be made based on the header in the stream. In this case the checksum method of this object will depend on whether a zlib or a gzip stream is detected.
Finally, negating the base value of window_bits indicates that a raw zlib stream is expected without any header or trailer. In this case the checksum method of this object will always return nil
. This is for use with other formats that use the deflate compressed data format such as zip. Such formats should provide their own check values.
If unspecified or nil
, window_bits defaults to 15
.
In all cases, Zlib::DataError is raised if the wrong stream format is found when reading.
This class has extremely limited seek capabilities. It is possible to seek with an offset of 0
and a whence of IO::SEEK_CUR
. As a result, the pos and tell methods also work as expected.
Due to certain optimizations within IO::Like#seek and if there is data in the read buffer, the seek method can be used to seek forward from the current stream position up to the end of the buffer. Unless it is known definitively how much data is in the buffer, it is best to avoid relying on this behavior.
If delegate also responds to rewind, then the rewind method of this class can be used to reset the whole stream back to the beginning. Using seek of this class to seek directly to offset 0
using IO::SEEK_SET
for whence will also work in this case.
Any other seeking attempts, will raise Errno::EINVAL exceptions.
NOTE: Due to limitations in Ruby’s finalization capabilities, the #close method is not automatically called when this object is garbage collected. Make sure to call #close when finished with this object.
348 349 350 351 352 353 354 355 356 357 |
# File 'lib/archive/support/zlib.rb', line 348 def initialize(delegate, window_bits = nil) @delegate = delegate @delegate_read_size = DEFAULT_DELEGATE_READ_SIZE @window_bits = window_bits @inflater = Zlib::Inflate.new(@window_bits) @inflate_buffer = '' @checksum = nil @compressed_size = nil @uncompressed_size = nil end |
Instance Attribute Details
#delegate ⇒ Object (readonly, protected)
The delegate object from which compressed data is read.
366 367 368 |
# File 'lib/archive/support/zlib.rb', line 366 def delegate @delegate end |
#delegate_read_size ⇒ Object
The number of bytes to read from the delegate object each time the internal read buffer is filled.
361 362 363 |
# File 'lib/archive/support/zlib.rb', line 361 def delegate_read_size @delegate_read_size end |
Class Method Details
.open(delegate, window_bits = nil) ⇒ Object
Creates a new instance of this class with the given arguments using #new and then passes the instance to the given block. The #close method is guaranteed to be called after the block completes.
Equivalent to #new if no block is given.
272 273 274 275 276 277 278 279 280 281 |
# File 'lib/archive/support/zlib.rb', line 272 def self.open(delegate, window_bits = nil) zr = new(delegate, window_bits) return zr unless block_given? begin yield(zr) ensure zr.close unless zr.closed? end end |
Instance Method Details
#checksum ⇒ Object
Returns the checksum computed over the data read from this stream.
NOTE: Refer to the documentation of #new concerning window_bits to learn what kind of checksum will be returned.
NOTE: The contents of the internal read buffer are immediately processed any time the internal buffer is filled, so this checksum is only accurate if all data has been read out of this object.
378 379 380 381 |
# File 'lib/archive/support/zlib.rb', line 378 def checksum return nil if @window_bits < 0 @inflater.closed? ? @checksum : @inflater.adler end |
#close ⇒ Object
Closes the reader.
Raises IOError if called more than once.
386 387 388 389 390 391 392 393 |
# File 'lib/archive/support/zlib.rb', line 386 def close super() @checksum = @inflater.adler @compressed_size = @inflater.total_in @uncompressed_size = @inflater.total_out @inflater.close nil end |
#compressed_size ⇒ Object
Returns the number of bytes sent to be compressed so far.
NOTE: This value is updated whenever the internal read buffer needs to be filled, not when data is read out of this stream.
399 400 401 |
# File 'lib/archive/support/zlib.rb', line 399 def compressed_size @inflater.closed? ? @compressed_size : @inflater.total_in end |
#unbuffered_read(length) ⇒ Object (private)
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/archive/support/zlib.rb', line 413 def unbuffered_read(length) if @inflate_buffer.empty? && @inflater.finished? then raise EOFError, 'end of file reached' end begin while @inflate_buffer.length < length && ! @inflater.finished? do @inflate_buffer << @inflater.inflate(delegate.read(@delegate_read_size)) end rescue Errno::EINTR, Errno::EAGAIN raise if @inflate_buffer.empty? end @inflate_buffer.slice!(0, length) end |
#unbuffered_seek(offset, whence = IO::SEEK_SET) ⇒ Object (private)
Allows resetting this object and the delegate object back to the beginning of the stream or reporting the current position in the stream.
Raises Errno::EINVAL unless offset is 0
and whence is either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if whence is IO::SEEK_SEK and the delegate object does not respond to the rewind method.
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/archive/support/zlib.rb', line 436 def unbuffered_seek(offset, whence = IO::SEEK_SET) unless offset == 0 && ((whence == IO::SEEK_SET && delegate.respond_to?(:rewind)) || whence == IO::SEEK_CUR) then raise Errno::EINVAL end case whence when IO::SEEK_SET delegate.rewind @inflater.close @inflater = Zlib::Inflate.new(@window_bits) @inflate_buffer = '' 0 when IO::SEEK_CUR @inflater.total_out - @inflate_buffer.length end end |
#uncompressed_size ⇒ Object
Returns the number of bytes of decompressed data produced so far.
NOTE: This value is updated whenever the internal read buffer needs to be filled, not when data is read out of this stream.
407 408 409 |
# File 'lib/archive/support/zlib.rb', line 407 def uncompressed_size @inflater.closed? ? @uncompressed_size : @inflater.total_out end |