Class: Archive::Zip::Codec::Deflate::Reader
- Inherits:
-
IO::LikeHelpers::DelegatedIO
- Object
- IO::LikeHelpers::DelegatedIO
- Archive::Zip::Codec::Deflate::Reader
- Defined in:
- lib/archive/zip/codec/deflate/reader.rb
Overview
Archive::Zip::Codec::Deflate#decompressor method.
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.
8192
Instance Attribute Summary collapse
-
#crc32 ⇒ Object
readonly
The CRC32 checksum of the uncompressed data read using this object.
-
#delegate_read_size ⇒ Object
The number of bytes to read from the delegate object each time the internal read buffer is filled.
Instance Method Summary collapse
-
#close ⇒ Object
Closes the reader.
-
#compressed_size ⇒ Object
Returns the number of bytes sent to be compressed so far.
-
#data_descriptor ⇒ Object
Returns an instance of Archive::Zip::DataDescriptor with information regarding the data which has passed through this object from the delegate object.
-
#initialize(delegate, autoclose: true, delegate_read_size: DEFAULT_DELEGATE_READ_SIZE) ⇒ Reader
constructor
Creates a new instance of this class.
- #read(length, buffer: nil, buffer_offset: 0) ⇒ Object
-
#seek(amount, whence = IO::SEEK_SET) ⇒ Object
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, autoclose: true, delegate_read_size: DEFAULT_DELEGATE_READ_SIZE) ⇒ Reader
Creates a new instance of this class. delegate must respond to the read method as an IO instance would.
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.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 48 def initialize( delegate, autoclose: true, delegate_read_size: DEFAULT_DELEGATE_READ_SIZE ) super(delegate, autoclose: autoclose) @delegate_read_size = delegate_read_size @read_buffer = "\0".b * @delegate_read_size @inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS) @inflate_buffer = '' @inflate_buffer_idx = 0 @compressed_size = nil @uncompressed_size = nil @crc32 = 0 end |
Instance Attribute Details
#crc32 ⇒ Object (readonly)
The CRC32 checksum of the uncompressed data read using this object.
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.
95 96 97 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 95 def crc32 @crc32 end |
#delegate_read_size ⇒ Object
The number of bytes to read from the delegate object each time the internal read buffer is filled.
67 68 69 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 67 def delegate_read_size @delegate_read_size end |
Instance Method Details
#close ⇒ Object
Closes the reader.
Raises IOError if called more than once.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 72 def close return nil if closed? result = super return result if Symbol === result @compressed_size = @inflater.total_in @uncompressed_size = @inflater.total_out @inflate_buffer = nil @inflate_buffer_idx = 0 # Avoid warnings by only attempting to close the inflater if it was # correctly finished. @inflater.close if @inflater.finished? 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.
101 102 103 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 101 def compressed_size @inflater.closed? ? @compressed_size : @inflater.total_in end |
#data_descriptor ⇒ Object
Returns an instance of Archive::Zip::DataDescriptor with information regarding the data which has passed through this object from the delegate object. It is recommended to call the close method before calling this in order to ensure that no further read operations change the state of this object.
118 119 120 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 118 def data_descriptor DataDescriptor.new(crc32, compressed_size, uncompressed_size) end |
#read(length, buffer: nil, buffer_offset: 0) ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 122 def read(length, buffer: nil, buffer_offset: 0) length = Integer(length) raise ArgumentError, 'length must be at least 0' if length < 0 if ! buffer.nil? if buffer_offset < 0 || buffer_offset >= buffer.bytesize raise ArgumentError, 'buffer_offset is not a valid buffer index' end if buffer.bytesize - buffer_offset < length raise ArgumentError, 'length is greater than available buffer space' end end assert_readable if @inflate_buffer_idx >= @inflate_buffer.size raise EOFError, 'end of file reached' if @inflater.finished? @inflate_buffer = begin result = super(@delegate_read_size, buffer: @read_buffer) return result if Symbol === result @inflater.inflate(@read_buffer[0, result]) rescue EOFError @inflater.inflate(nil) end @inflate_buffer_idx = 0 end available = @inflate_buffer.size - @inflate_buffer_idx length = available if available < length content = @inflate_buffer[@inflate_buffer_idx, length] @inflate_buffer_idx += length @crc32 = Zlib.crc32(content, @crc32) return content if buffer.nil? buffer[buffer_offset, length] = content return length end |
#seek(amount, whence = IO::SEEK_SET) ⇒ Object
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.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 168 def seek(amount, whence = IO::SEEK_SET) assert_open raise Errno::ESPIPE if amount != 0 || whence == IO::SEEK_END case whence when IO::SEEK_SET result = super return result if Symbol === result @inflater.reset @inflate_buffer_idx = @inflate_buffer.size @crc32 = 0 result when IO::SEEK_CUR @inflater.total_out - (@inflate_buffer.size - @inflate_buffer_idx) else raise Errno::EINVAL 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.
109 110 111 |
# File 'lib/archive/zip/codec/deflate/reader.rb', line 109 def uncompressed_size @inflater.closed? ? @uncompressed_size : @inflater.total_out end |