Class: Zlib::ZWriter
- Inherits:
-
Object
- Object
- Zlib::ZWriter
- Includes:
- IO::Like
- Defined in:
- lib/archive/support/zlib.rb
Overview
Zlib::ZWriter is a writable, IO-like object (includes IO::Like) which wraps other writable, IO-like objects in order to facilitate writing data to those objects using the deflate method of compression.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#delegate ⇒ Object
readonly
protected
The delegate object to which compressed data is written.
Class Method Summary collapse
-
.open(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = 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 written to this stream so far.
-
#close ⇒ Object
Closes the writer by finishing the compressed data and flushing it to the delegate.
-
#compressed_size ⇒ Object
Returns the number of bytes of compressed data produced so far.
-
#initialize(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil) ⇒ ZWriter
constructor
Creates a new instance of this class.
-
#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.
- #unbuffered_write(string) ⇒ Object private
-
#uncompressed_size ⇒ Object
Returns the number of bytes sent to be compressed so far.
Constructor Details
#initialize(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil) ⇒ ZWriter
Creates a new instance of this class. delegate must respond to the write method as an instance of IO would. level, window_bits, mem_level, and strategy are all passed directly to Zlib::Deflate.new().
The following descriptions of level, window_bits, mem_level, and strategy are based upon or pulled largely verbatim from descriptions found in zlib.h version 1.2.3 with changes made to account for different parameter names and to improve readability. 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 level parameter must be nil
, Zlib::DEFAULT_COMPRESSION, or between 0
and 9
: 1
gives best speed, 9
gives best compression, 0
gives no compression at all (the input data is simply copied a block at a time). Zlib::DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6
). If unspecified or nil
, level defaults to Zlib::DEFAULT_COMPRESSION.
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. A value of 8
indicates a small window which reduces memory usage but lowers the compression ratio while a value of 15
indicates a larger window which increases memory usage but raises the compression ratio. Modification of this base value for window_bits as noted below dictates what kind of compressed stream and 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 to be produced 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 to be produced with an appropriate header and trailer. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255
(unknown). In this case the checksum attribute of this object will be a crc32.
Finally, negating the base value of window_bits indicates that a raw zlib stream is to be produced 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
.
The mem_level parameter specifies how much memory should be allocated for the internal compression state. A value of 1
uses minimum memory but is slow and reduces compression ratio; a value of 9
uses maximum memory for optimal speed. The default value is 8
if unspecified or nil
.
The strategy parameter is used to tune the compression algorithm. It only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. The default value is Zlib::DEFAULT_STRATEGY if unspecified or nil
.
Use the value Zlib::DEFAULT_STRATEGY for normal data, Zlib::FILTERED for data produced by a filter (or predictor), Zlib::HUFFMAN_ONLY to force Huffman encoding only (no string match), Zlib::RLE to limit match distances to 1 (run-length encoding), or Zlib::FIXED to simplify decoder requirements.
The effect of Zlib::FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Zlib::DEFAULT_STRATEGY and Zlib::HUFFMAN_ONLY. Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better.
Zlib::RLE is designed to be almost as fast as Zlib::HUFFMAN_ONLY, but give better compression for PNG image data.
Zlib::FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications.
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.
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.
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.
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/archive/support/zlib.rb', line 138 def initialize(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil) @delegate = delegate @level = level @window_bits = window_bits @mem_level = mem_level @strategy = strategy @deflater = Zlib::Deflate.new(@level, @window_bits, @mem_level, @strategy) @deflate_buffer = '' @checksum = nil @compressed_size = nil @uncompressed_size = nil end |
Instance Attribute Details
#delegate ⇒ Object (readonly, protected)
The delegate object to which compressed data is written.
154 155 156 |
# File 'lib/archive/support/zlib.rb', line 154 def delegate @delegate end |
Class Method Details
.open(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = 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.
34 35 36 37 38 39 40 41 42 43 |
# File 'lib/archive/support/zlib.rb', line 34 def self.open(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil) zw = new(delegate, level, window_bits, mem_level, strategy) return zw unless block_given? begin yield(zw) ensure zw.close unless zw.closed? end end |
Instance Method Details
#checksum ⇒ Object
Returns the checksum computed over the data written to this stream so far.
NOTE: Refer to the documentation of #new concerning window_bits to learn what kind of checksum will be returned.
NOTE: Anything still in the internal write buffer has not been processed, so calling #flush prior to calling this method may be necessary for an accurate checksum.
166 167 168 169 |
# File 'lib/archive/support/zlib.rb', line 166 def checksum return nil if @window_bits < 0 @deflater.closed? ? @checksum : @deflater.adler end |
#close ⇒ Object
Closes the writer by finishing the compressed data and flushing it to the delegate.
Raises IOError if called more than once.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/archive/support/zlib.rb', line 175 def close flush() @deflate_buffer << @deflater.finish unless @deflater.finished? begin until @deflate_buffer.empty? do @deflate_buffer.slice!(0, delegate.write(@deflate_buffer)) end rescue Errno::EAGAIN, Errno::EINTR retry if write_ready? end @checksum = @deflater.adler @compressed_size = @deflater.total_out @uncompressed_size = @deflater.total_in @deflater.close super() nil end |
#compressed_size ⇒ Object
Returns the number of bytes of compressed data produced so far.
NOTE: This value is only updated when both the internal write buffer is flushed and there is enough data to produce a compressed block. It does not necessarily reflect the amount of data written to the delegate until this stream is closed however. Until then the only guarantee is that the value will be greater than or equal to 0
.
200 201 202 |
# File 'lib/archive/support/zlib.rb', line 200 def compressed_size @deflater.closed? ? @compressed_size : @deflater.total_out 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.
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/archive/support/zlib.rb', line 221 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 @deflater.finish @deflater.close @deflater = Zlib::Deflate.new( @level, @window_bits, @mem_level, @strategy ) @deflate_buffer = '' 0 when IO::SEEK_CUR @deflater.total_in end end |
#unbuffered_write(string) ⇒ Object (private)
243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/archive/support/zlib.rb', line 243 def unbuffered_write(string) # First try to write out the contents of the deflate buffer because if # that raises a failure we can let that pass up the call stack without # having polluted the deflater instance. until @deflate_buffer.empty? do @deflate_buffer.slice!(0, delegate.write(@deflate_buffer)) end # At this point we can deflate the given string into a new buffer and # behave as if it was written. @deflate_buffer = @deflater.deflate(string) string.length end |
#uncompressed_size ⇒ Object
Returns the number of bytes sent to be compressed so far.
NOTE: This value is only updated when the internal write buffer is flushed.
208 209 210 |
# File 'lib/archive/support/zlib.rb', line 208 def uncompressed_size @deflater.closed? ? @uncompressed_size : @deflater.total_in end |