2 # The Zlib module contains several classes for compressing and decompressing
3 # streams, and for working with "gzip" files.
7 # Following are the classes that are most likely to be of interest to the
14 # There are two important base classes for the classes above: Zlib::ZStream
15 # and Zlib::GzipFile. Everything else is an error class.
22 # The Ruby/zlib version string.
25 # The string which represents the version of zlib.h.
30 # The integers representing data types which Zlib::ZStream#data_type
33 # Zlib::NO_COMPRESSION
35 # Zlib::BEST_COMPRESSION
36 # Zlib::DEFAULT_COMPRESSION
37 # The integers representing compression levels which are an argument
38 # for Zlib::Deflate.new, Zlib::Deflate#deflate, and so on.
42 # Zlib::DEFAULT_STRATEGY
43 # The integers representing compression methods which are an argument
44 # for Zlib::Deflate.new and Zlib::Deflate#params.
48 # The integers representing memory levels which are an argument for
49 # Zlib::Deflate.new, Zlib::Deflate#params, and so on.
52 # The default value of windowBits which is an argument for
53 # Zlib::Deflate.new and Zlib::Inflate.new.
59 # The integers to control the output of the deflate stream, which are
60 # an argument for Zlib::Deflate#deflate and so on.
62 # These constants are missing!
80 # The return values of Zlib::GzipFile#os_code method.
85 constants :required => true do |c|
88 c.const 'ZLIB_VERSION', '%s', '(char *)', nil, to_s
90 c.const 'Z_NO_FLUSH', nil, nil, 'NO_FLUSH'
91 c.const 'Z_PARTIAL_FLUSH', nil, nil, 'PARTIAL_FLUSH'
92 c.const 'Z_SYNC_FLUSH', nil, nil, 'SYNC_FLUSH'
93 c.const 'Z_FULL_FLUSH', nil, nil, 'FULL_FLUSH'
94 c.const 'Z_FINISH', nil, nil, 'FINISH'
95 c.const 'Z_BLOCK', nil, nil, 'BLOCK'
97 c.const 'Z_OK', nil, nil, 'OK'
98 c.const 'Z_STREAM_END', nil, nil, 'STREAM_END'
99 c.const 'Z_NEED_DICT', nil, nil, 'NEED_DICT'
100 c.const 'Z_ERRNO', nil, nil, 'ERRNO'
101 c.const 'Z_STREAM_ERROR', nil, nil, 'STREAM_ERROR'
102 c.const 'Z_DATA_ERROR', nil, nil, 'DATA_ERROR'
103 c.const 'Z_MEM_ERROR', nil, nil, 'MEM_ERROR'
104 c.const 'Z_BUF_ERROR', nil, nil, 'BUF_ERROR'
105 c.const 'Z_VERSION_ERROR', nil, nil, 'VERSION_ERROR'
107 c.const 'Z_NO_COMPRESSION', nil, nil, 'NO_COMPRESSION'
108 c.const 'Z_BEST_SPEED', nil, nil, 'BEST_SPEED'
109 c.const 'Z_BEST_COMPRESSION', nil, nil, 'BEST_COMPRESSION'
110 c.const 'Z_DEFAULT_COMPRESSION', nil, nil, 'DEFAULT_COMPRESSION'
112 c.const 'Z_FILTERED', nil, nil, 'FILTERED'
113 c.const 'Z_HUFFMAN_ONLY', nil, nil, 'HUFFMAN_ONLY'
114 c.const 'Z_RLE', nil, nil, 'RLE'
115 c.const 'Z_FIXED', nil, nil, 'FIXED'
116 c.const 'Z_DEFAULT_STRATEGY', nil, nil, 'DEFAULT_STRATEGY'
118 c.const 'Z_DEFLATED', nil, nil, 'DEFLATED'
127 c.const 'MAX_MEM_LEVEL'
128 c.const 'DEF_MEM_LEVEL'
157 unless defined? OS_CODE then
162 unless defined? DEF_MEM_LEVEL then
163 DEF_MEM_LEVEL = MAX_MEM_LEVEL >= 8 ? 8 : MAX_MEM_LEVEL
166 class Error < StandardError; end
168 class StreamEnd < Error; end
169 class NeedDict < Error; end
170 class StreamError < Error; end
171 class DataError < Error; end
172 class BufError < Error; end
173 class VersionError < Error; end
174 class MemError < Error; end
177 # Zlib::ZStream is the abstract class for the stream which handles the
178 # compressed data. The operations are defined in the subclasses:
179 # Zlib::Deflate for compression, and Zlib::Inflate for decompression.
181 # An instance of Zlib::ZStream has one stream (struct zstream in the source)
182 # and two variable-length buffers which associated to the input (next_in) of
183 # the stream and the output (next_out) of the stream. In this document,
184 # "input buffer" means the buffer for input, and "output buffer" means the
187 # Data input into an instance of Zlib::ZStream are temporally stored into
188 # the end of input buffer, and then data in input buffer are processed from
189 # the beginning of the buffer until no more output from the stream is
190 # produced (i.e. until avail_out > 0 after processing). During processing,
191 # output buffer is allocated and expanded automatically to hold all output
194 # Some particular instance methods consume the data in output buffer and
195 # return them as a String.
197 # Here is an ascii art for describing above:
199 # +================ an instance of Zlib::ZStream ================+
201 # || +--------+ +-------+ +--------+ ||
202 # || +--| output |<---------|zstream|<---------| input |<--+ ||
203 # || | | buffer | next_out+-------+next_in | buffer | | ||
204 # || | +--------+ +--------+ | ||
206 # +===|======================================================|===+
209 # "output data" "input data"
211 # If an error occurs during processing input buffer, an exception which is a
212 # subclass of Zlib::Error is raised. At that time, both input and output
213 # buffer keep their conditions at the time when the error occurs.
215 # == Method Catalogue
217 # Many of the methods in this class are fairly low-level and unlikely to be
218 # of interest to users. In fact, users are unlikely to use this class
219 # directly; rather they will be interested in Zlib::Inflate and
222 # The higher level methods are listed below.
234 class ZStream < FFI::Struct
240 s.name "struct z_stream_s"
241 s.field :next_in, :pointer
242 s.field :avail_in, :uint
243 s.field :total_in, :ulong
245 s.field :next_out, :pointer
246 s.field :avail_out, :uint
247 s.field :total_out, :ulong
249 s.field :msg, :string
250 s.field :state, :pointer
252 s.field :zalloc, :pointer
253 s.field :zfree, :pointer
254 s.field :opaque, :pointer
256 s.field :data_type, :int
257 s.field :adler, :ulong
258 s.field :reserved, :ulong
263 # HACK from MRI's zlib.c
278 def self.inherited(subclass)
279 subclass.instance_variable_set :@layout, @layout
280 subclass.instance_variable_set :@size, @size
300 @flags & CLOSING == CLOSING
311 self[:next_out] = nil
318 # Closes the stream. All operations on the closed stream will raise an
323 warn "attempt to close uninitialized stream; ignored."
328 warn "attempt to close unfinished zstream; reset forced"
334 err = Zlib.send @func_end, pointer
336 Zlib.handle_error err, message
340 # HACK this may be wrong
342 @next_out.free unless @next_out.nil?
353 @next_out = MemoryPointer.new CHUNK if @next_out.nil?
354 @next_out.write_string "\000" * CHUNK
355 self[:next_out] = @next_out
357 have = CHUNK - self[:avail_out]
358 @output << @next_out.read_string(have)
360 self[:next_out] = @next_out # Zlib advances self[:next_out]
363 self[:avail_out] = CHUNK
367 # Finishes the stream and flushes output buffer. See Zlib::Deflate#finish
368 # and Zlib::Inflate#finish for details of this behavior.
377 # Returns true if the stream is finished.
380 @flags & FINISHED == FINISHED
384 # Flushes output buffer and returns all data in that buffer.
391 @flags & IN_STREAM == IN_STREAM
395 @input.nil? or @input.empty?
399 # The msg field of the struct
410 @flags & READY == READY
414 # Resets and initializes the stream. All data in both input and output
415 # buffer are discarded.
418 err = Zlib.send @func_reset, pointer
420 Zlib.handle_error err, message
432 if @input.nil? and data.empty? then
433 data_in = MemoryPointer.new 1
434 data_in.write_string "\000", 1
435 self[:next_in] = data_in
441 data_in = MemoryPointer.new @input.length
442 data_in.write_string @input, @input.length
443 self[:next_in] = data_in
444 self[:avail_in] = @input.length
447 expand_output if self[:avail_out] == 0
450 err = Zlib.send @func_run, pointer, flush
452 available = self[:avail_out]
454 expand_output # HACK does this work when err is set?
456 if err == Zlib::STREAM_END then
462 unless err == Zlib::OK then
463 if flush != Zlib::FINISH and err == Zlib::BUF_ERROR and
464 self[:avail_out] > 0 then
469 if self[:avail_in] > 0 then
470 @input = self[:next_in].read_string(self[:avail_in]) + @input
473 Zlib.handle_error err, message
476 if available > 0 then
484 if self[:avail_in] > 0 then
485 @input = self[:next_in].read_string self[:avail_in]
493 # Returns the number of bytes consumed
500 # Returns the number bytes processed
510 # deflateInit2 is a macro pointing to deflateInit2_
511 attach_function 'deflateInit2_', :deflateInit2_, [
512 :pointer, # z_streamp strm
515 :int, # int windowBits
518 :string, # ZLIB_VERSION
519 :int # (int)sizeof(z_stream)
522 def self.deflateInit2(stream, level, method, window_bits, mem_level, strategy)
523 deflateInit2_ stream, level, method, window_bits, mem_level, strategy,
524 ZLIB_VERSION, ZStream.size
527 attach_function 'deflate', :deflate, [:pointer, :int], :int
528 attach_function 'deflateEnd', :deflateEnd, [:pointer], :int
529 attach_function 'deflateParams', :deflateParams, [:pointer, :int, :int],
531 attach_function 'deflateReset', :deflateReset, [:pointer], :int
532 attach_function 'deflateSetDictionary', :deflateSetDictionary,
533 [:pointer, :string, :uint], :int
535 # inflateInit2 is a macro pointing to inflateInit2_
536 attach_function 'inflateInit2_', :inflateInit2_,
537 [:pointer, :int, :string, :int], :int
539 def self.inflateInit2(stream, window_bits)
540 inflateInit2_ stream, window_bits, ZLIB_VERSION, ZStream.size
543 attach_function 'inflate', :inflate, [:pointer, :int], :int
544 attach_function 'inflateEnd', :inflateEnd, [:pointer], :int
545 attach_function 'inflateReset', :inflateReset, [:pointer], :int
546 attach_function 'inflateSetDictionary', :inflateSetDictionary,
547 [:pointer, :string, :uint], :int
549 attach_function 'adler32', :adler32_c, [:ulong, :string, :uint],
551 attach_function 'crc32', :crc32_c, [:ulong, :string, :uint],
553 attach_function 'get_crc_table', :get_crc_table_c, [], :pointer
555 attach_function 'zError', :zError, [:int], :string
557 # Chunk size for inflation and deflation
565 GZ_EXTRAFLAG_FAST = 0x4
566 GZ_EXTRAFLAG_SLOW = 0x2
569 # Zlib::Deflate is the class for compressing data. See Zlib::ZStream for
572 class Deflate < ZStream
575 # Compresses the given +string+. Valid values of level are
576 # <tt>Zlib::NO_COMPRESSION</tt>, <tt>Zlib::BEST_SPEED</tt>,
577 # <tt>Zlib::BEST_COMPRESSION</tt>, <tt>Zlib::DEFAULT_COMPRESSION</tt>, and
578 # an integer from 0 to 9.
580 # This method is almost equivalent to the following code:
582 # def deflate(string, level)
583 # z = Zlib::Deflate.new(level)
584 # dst = z.deflate(string, Zlib::FINISH)
589 def self.deflate(data, level = Zlib::DEFAULT_COMPRESSION)
592 zipped = deflator.deflate data, Zlib::FINISH
600 # Creates a new deflate stream for compression. See zlib.h for details of
601 # each argument. If an argument is nil, the default value of that argument
604 def initialize(level = Zlib::DEFAULT_COMPRESSION,
605 window_bits = Zlib::MAX_WBITS,
606 mem_level = Zlib::DEF_MEM_LEVEL,
607 strategy = Zlib::DEFAULT_STRATEGY)
608 level ||= Zlib::DEFAULT_COMPRESSION
609 window_bits ||= Zlib::MAX_WBITS
610 mem_level ||= Zlib::DEF_MEM_LEVEL
611 strategy ||= Zlib::DEFAULT_STRATEGY
615 @func_end = :deflateEnd
616 @func_reset = :deflateReset
619 err = Zlib.deflateInit2(pointer, level, Zlib::DEFLATED,
620 window_bits, mem_level, strategy)
622 Zlib.handle_error err, message
631 do_deflate data, Zlib::NO_FLUSH
637 # Inputs +string+ into the deflate stream and returns the output from the
638 # stream. On calling this method, both the input and the output buffers
639 # of the stream are flushed. If +string+ is nil, this method finishes the
640 # stream, just like Zlib::ZStream#finish.
642 # The value of +flush+ should be either <tt>Zlib::NO_FLUSH</tt>,
643 # <tt>Zlib::SYNC_FLUSH</tt>, <tt>Zlib::FULL_FLUSH</tt>, or
644 # <tt>Zlib::FINISH</tt>. See zlib.h for details.
646 def deflate(data, flush = Zlib::NO_FLUSH)
647 do_deflate data, flush
653 # Performs the deflate operation and leaves the compressed data in the
656 def do_deflate(data, flush)
660 data = StringValue data
662 if flush != Zlib::NO_FLUSH or not data.empty? then # prevent BUF_ERROR
669 # Finishes compressing the deflate input stream and returns the output
679 # This method is equivalent to <tt>deflate('', flush)</tt>. If flush is
680 # omitted, <tt>Zlib::SYNC_FLUSH</tt> is used as flush. This method is
681 # just provided to improve the readability of your Ruby program.
683 def flush(flush = Zlib::SYNC_FLUSH)
684 run '', flush unless flush == Zlib::NO_FLUSH
690 # Changes the parameters of the deflate stream. See zlib.h for details.
691 # The output from the stream by changing the params is preserved in output
694 def params(level, strategy)
695 err = Zlib.deflateParams pointer, level, strategy
697 raise Zlib::BufError, 'buffer expansion not implemented' if
698 err == Zlib::BUF_ERROR
700 Zlib.handle_error err, message
706 # Sets the preset dictionary and returns +dictionary+. This method is
707 # available just only after Zlib::Deflate.new or Zlib::ZStream#reset
708 # method was called. See zlib.h for details.
710 def set_dictionary(dictionary)
711 dict = StringValue dictionary
713 err = Zlib.deflateSetDictionary pointer, dict, dict.length
715 Zlib.handle_error err, message
723 # Zlib::GzipFile is an abstract class for handling a gzip formatted
724 # compressed file. The operations are defined in the subclasses,
725 # Zlib::GzipReader for reading, and Zlib::GzipWriter for writing.
727 # GzipReader should be used by associating an IO, or IO-like, object.
731 SYNC = Zlib::ZStream::UNUSED
732 HEADER_FINISHED = Zlib::ZStream::UNUSED << 1
733 FOOTER_FINISHED = Zlib::ZStream::UNUSED << 2
740 FLAG_UNKNOWN_MASK = 0xc0
750 # Base class of errors that occur when processing GZIP files.
752 class Error < Zlib::Error; end
755 # Raised when gzip file footer is not found.
757 class NoFooter < Error; end
760 # Raised when the CRC checksum recorded in gzip file footer is not
761 # equivalent to the CRC checksum of the actual uncompressed data.
763 class CRCError < Error; end
766 # Raised when the data length recorded in the gzip file footer is not
767 # equivalent to the length of the actual uncompressed data.
769 class LengthError < Error; end
772 # Accessor for the underlying ZStream
774 attr_reader :zstream # :nodoc:
777 # See Zlib::GzipReader#wrap and Zlib::GzipWriter#wrap.
786 obj.close if obj.zstream.ready?
797 @os_code = Zlib::OS_CODE
801 # Closes the GzipFile object. This method calls close method of the
802 # associated IO object. Returns the associated IO object.
807 io.close if io.respond_to? :close
820 # Returns comments recorded in the gzip file header, or nil if the
821 # comment is not present.
824 raise Error, 'closed gzip stream' if @io.nil?
830 return if @zstream.closing?
832 @zstream.flags |= Zlib::ZStream::CLOSING
842 # Closes the GzipFile object. Unlike Zlib::GzipFile#close, this method
843 # never calls the close method of the associated IO object. Returns the
844 # associated IO object.
858 @zstream.finished? and @zstream.output.empty? # HACK I think
862 @zstream.flags & Zlib::GzipFile::FOOTER_FINISHED ==
863 Zlib::GzipFile::FOOTER_FINISHED
867 @zstream.flags & Zlib::GzipFile::HEADER_FINISHED ==
868 Zlib::GzipFile::HEADER_FINISHED
872 # Returns last modification time recorded in the gzip file header.
879 # Returns original filename recorded in the gzip file header, or +nil+ if
880 # original filename is not present.
883 raise Error, 'closed gzip stream' if @io.nil?
891 # Zlib::GzipReader is the class for reading a gzipped file. GzipReader
892 # should be used an IO, or -IO-lie, object.
894 # Zlib::GzipReader.open('hoge.gz') {|gz|
898 # File.open('hoge.gz') do |f|
899 # gz = Zlib::GzipReader.new(f)
904 # == Method Catalogue
906 # The following methods in Zlib::GzipReader are just like their counterparts
907 # in IO, but they raise Zlib::Error or Zlib::GzipFile::Error exception if an
908 # error was found in the gzip file.
923 # Be careful of the footer of the gzip file. A gzip file has the checksum of
924 # pre-compressed data in its footer. GzipReader checks all uncompressed data
925 # against that checksum at the following cases, and if it fails, raises
926 # <tt>Zlib::GzipFile::NoFooter</tt>, <tt>Zlib::GzipFile::CRCError</tt>, or
927 # <tt>Zlib::GzipFile::LengthError</tt> exception.
929 # - When an reading request is received beyond the end of file (the end of
930 # compressed data). That is, when Zlib::GzipReader#read,
931 # Zlib::GzipReader#gets, or some other methods for reading returns nil.
932 # - When Zlib::GzipFile#close method is called after the object reaches the
934 # - When Zlib::GzipReader#unused method is called after the object reaches
937 # The rest of the methods are adequately described in their own
940 class GzipReader < GzipFile # HACK use a buffer class
943 # Creates a GzipReader object associated with +io+. The GzipReader object
944 # reads gzipped data from +io+, and parses/decompresses them. At least,
945 # +io+ must have a +read+ method that behaves same as the +read+ method in
948 # If the gzip file header is incorrect, raises an Zlib::GzipFile::Error
954 @zstream = Zlib::Inflate.new -Zlib::MAX_WBITS
964 @zstream.flags |= Zlib::GzipFile::FOOTER_FINISHED
966 footer = @zstream.input.slice! 0, 8
967 rest = @io.read 8 - footer.length
968 footer << rest if rest
970 raise NoFooter, 'footer is not found' unless footer.length == 8
972 crc, length = footer.unpack 'VV'
974 @zstream[:total_in] += 8 # to rewind correctly
976 raise CRCError, 'invalid compressed data -- crc error' unless @crc == crc
978 raise LengthError, 'invalid compressed data -- length error' unless
979 length == @zstream.total_out
983 check_footer if @zstream.finished? and not footer_finished?
987 @zstream.finished? and @zstream.input_empty?
991 @zstream[:total_out] - @buffer.length
995 # See Zlib::GzipReader documentation for a description.
997 def read(length = nil)
1000 while chunk = @io.read(CHUNK) do
1001 inflated = @zstream.inflate(chunk)
1002 @crc = Zlib.crc32 inflated, @crc
1005 break if length and data.length > length
1009 @buffer = data.slice! length..-1
1014 check_footer if @zstream.finished? and not footer_finished?
1017 rescue Zlib::Error => e
1018 raise GzipFile::Error, e.message
1022 header = @io.read 10
1024 raise Error, 'not in gzip format' unless header.length == 10
1026 magic1, magic2, method, flags, @mtime, extra_flags, @os_code =
1027 header.unpack 'CCCCVCC'
1029 unless magic1 == Zlib::GzipFile::MAGIC1 and
1030 magic2 == Zlib::GzipFile::MAGIC2 then
1031 raise Error, 'not in gzip format'
1034 unless method == Zlib::GzipFile::METHOD_DEFLATE then
1035 raise Error, "unsupported compression method #{method}"
1038 if flags & Zlib::GzipFile::FLAG_MULTIPART ==
1039 Zlib::GzipFile::FLAG_MULTIPART then
1040 raise Error, 'multi-part gzip file is not supported'
1043 if flags & Zlib::GzipFile::FLAG_ENCRYPT ==
1044 Zlib::GzipFile::FLAG_ENCRYPT then
1045 raise Error, 'encrypted gzip file is not supported'
1048 if flags & Zlib::GzipFile::FLAG_UNKNOWN_MASK ==
1049 Zlib::GzipFile::FLAG_UNKNOWN_MASK then
1050 raise Error, "unknown flags 0x#{flags.to_s 16}"
1053 if extra_flags & Zlib::GzipFile::EXTRAFLAG_FAST ==
1054 Zlib::GzipFile::EXTRAFLAG_FAST then
1055 @level = Zlib::BEST_SPEED
1056 elsif extra_flags & Zlib::GzipFile::EXTRAFLAG_SLOW ==
1057 Zlib::GzipFile::EXTRAFLAG_SLOW then
1058 @level = Zlib::BEST_COMPRESSION
1060 @level = Zlib::DEFAULT_COMPRESSION
1063 if flags & Zlib::GzipFile::FLAG_EXTRA == Zlib::GzipFile::FLAG_EXTRA then
1065 raise Zlib::GzipFile::Error, 'unexpected end of file' if
1066 length.nil? or length.length != 2
1068 length, = length.unpack 'v'
1070 extra = @io.read length + 2
1072 raise Zlib::GzipFile::Error, 'unexpected end of file' if
1073 extra.nil? or extra.length != length + 2
1076 if flags & Zlib::GzipFile::FLAG_ORIG_NAME ==
1077 Zlib::GzipFile::FLAG_ORIG_NAME then
1088 if flags & Zlib::GzipFile::FLAG_COMMENT ==
1089 Zlib::GzipFile::FLAG_COMMENT then
1104 # Zlib::GzipWriter is a class for writing gzipped files. GzipWriter should
1105 # be used with an instance of IO, or IO-like, object.
1109 # Zlib::GzipWriter.open('hoge.gz') do |gz|
1110 # gz.write 'jugemu jugemu gokou no surikire...'
1113 # File.open('hoge.gz', 'w') do |f|
1114 # gz = Zlib::GzipWriter.new(f)
1115 # gz.write 'jugemu jugemu gokou no surikire...'
1119 # NOTE: Due to the limitation of Ruby's finalizer, you must explicitly close
1120 # GzipWriter objects by Zlib::GzipWriter#close etc. Otherwise, GzipWriter
1121 # will be not able to write the gzip footer and will generate a broken gzip
1124 class GzipWriter < GzipFile # HACK use a buffer class
1129 attr_writer :comment
1132 # Set the original name
1134 attr_writer :orig_name
1137 # Creates a GzipWriter object associated with +io+. +level+ and +strategy+
1138 # should be the same as the arguments of Zlib::Deflate.new. The
1139 # GzipWriter object writes gzipped data to +io+. At least, +io+ must
1140 # respond to the +write+ method that behaves same as write method in IO
1143 def initialize(io, level = Zlib::DEFAULT_COMPRESSION,
1144 strategy = Zlib::DEFAULT_STRATEGY)
1147 @zstream = Zlib::Deflate.new level, -Zlib::MAX_WBITS,
1148 Zlib::DEF_MEM_LEVEL, strategy
1156 make_header unless header_finished?
1158 @zstream.run '', Zlib::FINISH
1168 # Flushes all the internal buffers of the GzipWriter object. The meaning
1169 # of +flush+ is same as in Zlib::Deflate#deflate.
1170 # <tt>Zlib::SYNC_FLUSH</tt> is used if +flush+ is omitted. It is no use
1171 # giving flush <tt>Zlib::NO_FLUSH</tt>.
1178 # Writes out a gzip header
1184 flags |= Zlib::GzipFile::FLAG_ORIG_NAME if @orig_name
1185 flags |= Zlib::GzipFile::FLAG_COMMENT if @comment
1187 extra_flags |= Zlib::GzipFile::EXTRAFLAG_FAST if
1188 @level == Zlib::BEST_SPEED
1190 extra_flags |= Zlib::GzipFile::EXTRAFLAG_SLOW if
1191 @level == Zlib::BEST_COMPRESSION
1194 Zlib::GzipFile::MAGIC1, # byte 0
1195 Zlib::GzipFile::MAGIC2, # byte 1
1196 Zlib::GzipFile::METHOD_DEFLATE, # byte 2
1198 @mtime.to_i, # bytes 4-7
1199 extra_flags, # byte 8
1205 @io.write "#{@orig_name}\0" if @orig_name
1206 @io.write "#{@comment}\0" if @comment
1208 @zstream.flags |= Zlib::GzipFile::HEADER_FINISHED
1212 # Writes out a gzip footer
1217 @zstream.total_in, # bytes 4-7
1222 @zstream.flags |= Zlib::GzipFile::FOOTER_FINISHED
1226 # Sets the modification time of this file
1229 if header_finished? then
1230 raise Zlib::GzipFile::Error, 'header is already written'
1233 @mtime = Integer time
1237 @zstream.flags & Zlib::GzipFile::SYNC == Zlib::GzipFile::SYNC
1244 make_header unless header_finished?
1248 if data.length > 0 or sync? then
1249 @crc = Zlib.crc32_c @crc, data, data.length
1251 flush = sync? ? Zlib::SYNC_FLUSH : Zlib::NO_FLUSH
1253 @zstream.run data, flush
1265 data = @zstream.detatch_output
1267 unless data.empty? then
1269 @io.flush if sync? and io.respond_to :flush
1276 # Zlib:Inflate is the class for decompressing compressed data. Unlike
1277 # Zlib::Deflate, an instance of this class is not able to duplicate (clone,
1280 class Inflate < ZStream
1283 # Decompresses +string+. Raises a Zlib::NeedDict exception if a preset
1284 # dictionary is needed for decompression.
1286 # This method is almost equivalent to the following code:
1288 # def inflate(string)
1289 # zstream = Zlib::Inflate.new
1290 # buf = zstream.inflate(string)
1296 def self.inflate(data)
1299 unzipped = inflator.inflate data
1307 # Creates a new inflate stream for decompression. See zlib.h for details
1308 # of the argument. If +window_bits+ is +nil+, the default value is used.
1310 def initialize(window_bits = Zlib::MAX_WBITS)
1313 @func_end = :inflateEnd
1314 @func_reset = :inflateReset
1315 @func_run = :inflate
1317 err = Zlib.inflateInit2 pointer, window_bits
1319 Zlib.handle_error err, message # HACK
1325 # Inputs +string+ into the inflate stream just like Zlib::Inflate#inflate,
1326 # but returns the Zlib::Inflate object itself. The output from the stream
1327 # is preserved in output buffer.
1330 string = StringValue string unless string.nil?
1333 unless string.nil? then
1338 run string, Zlib::SYNC_FLUSH
1343 # Inputs +string+ into the inflate stream and returns the output from the
1344 # stream. Calling this method, both the input and the output buffer of
1345 # the stream are flushed. If string is +nil+, this method finishes the
1346 # stream, just like Zlib::ZStream#finish.
1348 # Raises a Zlib::NeedDict exception if a preset dictionary is needed to
1349 # decompress. Set the dictionary by Zlib::Inflate#set_dictionary and then
1350 # call this method again with an empty string. (<i>???</i>)
1353 data = Type.coerce_to data, String, :to_str unless data.nil?
1357 unzipped = detatch_output
1366 run '', Zlib::FINISH
1367 elsif not data.empty? then
1368 run data, Zlib::SYNC_FLUSH
1371 unzipped = detatch_output
1373 if finished? and not @input.nil? then
1382 # Sets the preset dictionary and returns +string+. This method is
1383 # available just only after a Zlib::NeedDict exception was raised. See
1384 # zlib.h for details.
1386 def set_dictionary(dictionary)
1387 dict = StringValue dictionary
1389 err = Zlib.inflateSetDictionary pointer, dict, dict.length
1391 Zlib.handle_error err, message
1399 # Calculates Alder-32 checksum for +string+, and returns updated value of
1400 # +adler+. If +string+ is omitted, it returns the Adler-32 initial value. If
1401 # +adler+ is omitted, it assumes that the initial value is given to +adler+.
1403 def self.adler32(string = "", sum = 1)
1404 do_checksum(string, sum, :adler32_c)
1408 # Returns the table for calculating CRC checksum as an array.
1411 get_crc_table_c.read_array_of_long(256).map do |x|
1412 x >= 0 ? x : 2 ** 32 + x # HACK convert back to unsigned
1417 # Calculates CRC checksum for +string+, and returns updated value of +crc+.
1418 # If +string+ is omitted, it returns the CRC initial value. If +crc+ is
1419 # omitted, it assumes that the initial value is given to +crc+.
1421 def self.crc32(string = "", sum = 0)
1422 do_checksum(string, sum, :crc32_c)
1426 # Generates a checksum using function +type+
1428 def self.do_checksum(string, vsum, type)
1430 raise RangeError if vsum >= (2 ** 128)
1431 raise "Explain why you did this: email ephoenix@engineyard.com" if vsum < 0
1436 sum = send(type, 0, nil, 0)
1439 send(type, sum, string, string ? string.size : 0)
1443 # Raises an exception of the appropriate class
1445 def self.handle_error(error, message = nil)
1446 return if error == Zlib::OK
1448 message = zError error if message.nil?
1451 when Zlib::STREAM_END then Zlib::StreamEnd
1452 when Zlib::NEED_DICT then Zlib::NeedDict
1453 when Zlib::STREAM_ERROR then Zlib::StreamError
1454 when Zlib::DATA_ERROR then Zlib::DataError
1455 when Zlib::BUF_ERROR then Zlib::BufError
1456 when Zlib::MEM_ERROR then Zlib::MemError
1457 when Errno then Errno.handle message
1459 message = "unknown zlib error #{error}: #{message}"
1463 raise klass, message