Change soft-fail to use the config, rather than env
[rbx.git] / lib / zlib.rb.ffi
blobf3ce5962099a0b17c89866f9e0e16fb3751823b6
1 ##
2 # The Zlib module contains several classes for compressing and decompressing
3 # streams, and for working with "gzip" files.
5 # == Classes
7 # Following are the classes that are most likely to be of interest to the
8 # user:
9 # - Zlib::Inflate
10 # - Zlib::Deflate
11 # - Zlib::GzipReader
12 # - Zlib::GzipWriter
14 # There are two important base classes for the classes above: Zlib::ZStream
15 # and Zlib::GzipFile.  Everything else is an error class.
17 # == Constants
19 # Here's a list.
21 #   Zlib::VERSION
22 #       The Ruby/zlib version string.
24 #   Zlib::ZLIB_VERSION
25 #       The string which represents the version of zlib.h.
27 #   Zlib::BINARY
28 #   Zlib::ASCII
29 #   Zlib::UNKNOWN
30 #       The integers representing data types which Zlib::ZStream#data_type
31 #       method returns.
33 #   Zlib::NO_COMPRESSION
34 #   Zlib::BEST_SPEED
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.
40 #   Zlib::FILTERED
41 #   Zlib::HUFFMAN_ONLY
42 #   Zlib::DEFAULT_STRATEGY
43 #       The integers representing compression methods which are an argument
44 #       for Zlib::Deflate.new and Zlib::Deflate#params.
46 #   Zlib::DEF_MEM_LEVEL
47 #   Zlib::MAX_MEM_LEVEL
48 #       The integers representing memory levels which are an argument for
49 #       Zlib::Deflate.new, Zlib::Deflate#params, and so on.
51 #   Zlib::MAX_WBITS
52 #       The default value of windowBits which is an argument for
53 #       Zlib::Deflate.new and Zlib::Inflate.new.
55 #   Zlib::NO_FLUSH
56 #   Zlib::SYNC_FLUSH
57 #   Zlib::FULL_FLUSH
58 #   Zlib::FINISH
59 #       The integers to control the output of the deflate stream, which are
60 #       an argument for Zlib::Deflate#deflate and so on.
61 #--
62 # These constants are missing!
64 #   Zlib::OS_CODE
65 #   Zlib::OS_MSDOS
66 #   Zlib::OS_AMIGA
67 #   Zlib::OS_VMS
68 #   Zlib::OS_UNIX
69 #   Zlib::OS_VMCMS
70 #   Zlib::OS_ATARI
71 #   Zlib::OS_OS2
72 #   Zlib::OS_MACOS
73 #   Zlib::OS_ZSYSTEM
74 #   Zlib::OS_CPM
75 #   Zlib::OS_TOPS20
76 #   Zlib::OS_WIN32
77 #   Zlib::OS_QDOS
78 #   Zlib::OS_RISCOS
79 #   Zlib::OS_UNKNOWN
80 #       The return values of Zlib::GzipFile#os_code method.
82 module Zlib
84   @@@
85   constants :required => true do |c|
86     c.include 'zlib.h'
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'
119   end
120   @@@
122   @@@
123   constants do |c|
124     c.include 'zconf.h'
126     c.const 'MAX_WBITS'
127     c.const 'MAX_MEM_LEVEL'
128     c.const 'DEF_MEM_LEVEL'
129   end
130   @@@
132   OS_MSDOS    = 0x00
133   OS_AMIGA    = 0x01
134   OS_VMS      = 0x02
135   OS_UNIX     = 0x03
136   OS_ATARI    = 0x05
137   OS_OS2      = 0x06
138   OS_MACOS    = 0x07
139   OS_TOPS20   = 0x0a
140   OS_WIN32    = 0x0b
141   
142   OS_VMCMS    = 0x04
143   OS_ZSYSTEM  = 0x08
144   OS_CPM      = 0x09
145   OS_QDOS     = 0x0c
146   OS_RISCOS   = 0x0d
147   OS_UNKNOWN  = 0xff
149   @@@
150   constants do |c|
151     c.include 'zlib.h'
153     c.const 'OS_CODE'
154   end
155   @@@
157   unless defined? OS_CODE then
158     OS_CODE = OS_UNIX
159   end
161   # from zutil.h
162   unless defined? DEF_MEM_LEVEL then
163     DEF_MEM_LEVEL = MAX_MEM_LEVEL >= 8 ? 8 : MAX_MEM_LEVEL
164   end
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
176   ##
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.
180   #
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
185   # buffer for output.
186   #
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
192   # data.
193   #
194   # Some particular instance methods consume the data in output buffer and
195   # return them as a String.
196   #
197   # Here is an ascii art for describing above:
198   #
199   #    +================ an instance of Zlib::ZStream ================+
200   #    ||                                                            ||
201   #    ||     +--------+          +-------+          +--------+      ||
202   #    ||  +--| output |<---------|zstream|<---------| input  |<--+  ||
203   #    ||  |  | buffer |  next_out+-------+next_in   | buffer |   |  ||
204   #    ||  |  +--------+                             +--------+   |  ||
205   #    ||  |                                                      |  ||
206   #    +===|======================================================|===+
207   #        |                                                      |
208   #        v                                                      |
209   #    "output data"                                         "input data"
210   #
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.
214   #
215   # == Method Catalogue
216   #
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
220   # Zlib::Deflate.
221   #
222   # The higher level methods are listed below.
223   #
224   # - #total_in
225   # - #total_out
226   # - #data_type
227   # - #adler
228   # - #reset
229   # - #finish
230   # - #finished?
231   # - #close
232   # - #closed?
234   class ZStream < FFI::Struct
236     @@@
237     struct do |s|
238       s.include "zlib.h"
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
259     end
260     @@@
262     #--
263     # HACK from MRI's zlib.c
264     #++
266     READY = 0x1
267     IN_STREAM = 0x2
268     FINISHED = 0x4
269     CLOSING = 0x8
270     UNUSED = 0x10
272     attr_accessor :flags
274     attr_reader :input
276     attr_reader :output
278     def self.inherited(subclass)
279       subclass.instance_variable_set :@layout, @layout
280       subclass.instance_variable_set :@size, @size
281     end
283     def initialize
284       super
286       self[:avail_in] = 0
287       self[:avail_out] = 0
288       self[:next_in] = nil
289       self[:opaque] = nil
290       self[:zalloc] = nil
291       self[:zfree] = nil
293       reset_input
294       @output = nil
295       @flags = 0
296       @func = nil
297     end
299     def closing?
300       @flags & CLOSING == CLOSING
301     end
303     def detatch_output
304       if @output.nil? then
305         data = ''
306       else
307         data = @output
309         @output = nil
310         self[:avail_out] = 0
311         self[:next_out] = nil
312       end
314       data
315     end
317     ##
318     # Closes the stream. All operations on the closed stream will raise an
319     # exception.
321     def end
322       unless ready? then
323         warn "attempt to close uninitialized stream; ignored."
324         return nil
325       end
327       if in_stream? then
328         warn "attempt to close unfinished zstream; reset forced"
329         reset
330       end
332       reset_input
334       err = Zlib.send @func_end, pointer
336       Zlib.handle_error err, message
338       @flags = 0
340       # HACK this may be wrong
341       @output = nil
342       @next_out.free unless @next_out.nil?
343       @next_out = nil
345       nil
346     end
348     alias :close :end
350     def expand_output
351       if @output.nil? then
352         @output = ''
353         @next_out = MemoryPointer.new CHUNK if @next_out.nil?
354         @next_out.write_string "\000" * CHUNK
355         self[:next_out] = @next_out
356       else
357         have = CHUNK - self[:avail_out]
358         @output << @next_out.read_string(have)
360         self[:next_out] = @next_out # Zlib advances self[:next_out]
361       end
363       self[:avail_out] = CHUNK
364     end
366     ##
367     # Finishes the stream and flushes output buffer. See Zlib::Deflate#finish
368     # and Zlib::Inflate#finish for details of this behavior.
370     def finish
371       run '', Zlib::FINISH
373       detatch_output
374     end
376     ##
377     # Returns true if the stream is finished.
379     def finished?
380       @flags & FINISHED == FINISHED
381     end
383     ##
384     # Flushes output buffer and returns all data in that buffer.
386     def flush_next_out
387       detatch_output
388     end
390     def in_stream?
391       @flags & IN_STREAM == IN_STREAM
392     end
394     def input_empty?
395       @input.nil? or @input.empty?
396     end
398     ##
399     # The msg field of the struct
401     def message
402       self[:msg]
403     end
405     def ready
406       @flags |= READY
407     end
409     def ready?
410       @flags & READY == READY
411     end
413     ##
414     # Resets and initializes the stream. All data in both input and output
415     # buffer are discarded.
417     def reset
418       err = Zlib.send @func_reset, pointer
420       Zlib.handle_error err, message
422       @flags = READY
424       reset_input
425     end
427     def reset_input
428       @input = nil
429     end
431     def run(data, flush)
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
436         self[:avail_in] = 0
437       else
438         @input ||= ''
439         @input << data
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
445       end
447       expand_output if self[:avail_out] == 0
449       loop do
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
457           @flags &= ~IN_STREAM
458           @flags |= FINISHED
459           break
460         end
462         unless err == Zlib::OK then
463           if flush != Zlib::FINISH and err == Zlib::BUF_ERROR and
464              self[:avail_out] > 0 then
465             @flags |= IN_STREAM
466             break
467           end
469           if self[:avail_in] > 0 then
470             @input = self[:next_in].read_string(self[:avail_in]) + @input
471           end
473           Zlib.handle_error err, message
474         end
476         if available > 0 then
477           @flags |= IN_STREAM
478           break
479         end
480       end
482       reset_input
484       if self[:avail_in] > 0 then
485         @input = self[:next_in].read_string self[:avail_in]
486       end
487     ensure
488       data_in.free
489       self[:next_in] = nil
490     end
492     ##
493     # Returns the number of bytes consumed
495     def total_in
496       self[:total_in]
497     end
499     ##
500     # Returns the number bytes processed
502     def total_out
503       self[:total_out]
504     end
506   end
508   set_ffi_lib 'libz'
510   # deflateInit2 is a macro pointing to deflateInit2_
511   attach_function 'deflateInit2_', :deflateInit2_, [
512                     :pointer, # z_streamp strm
513                     :int,     # int level
514                     :int,     # int method
515                     :int,     # int windowBits
516                     :int,     # int memLevel
517                     :int,     # int strategy
518                     :string,  # ZLIB_VERSION
519                     :int      # (int)sizeof(z_stream)
520                   ], :int
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
525   end
527   attach_function 'deflate',        :deflate,         [:pointer, :int], :int
528   attach_function 'deflateEnd',     :deflateEnd,      [:pointer],       :int
529   attach_function 'deflateParams',  :deflateParams,   [:pointer, :int, :int],
530                   :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
541   end
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],
550                   :ulong
551   attach_function 'crc32',          :crc32_c,         [:ulong, :string, :uint],
552                   :ulong
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
559   CHUNK = 1024
561   #--
562   # HACK from zlib.c
563   #++
565   GZ_EXTRAFLAG_FAST = 0x4
566   GZ_EXTRAFLAG_SLOW = 0x2
568   ##
569   # Zlib::Deflate is the class for compressing data.  See Zlib::ZStream for
570   # more information.
572   class Deflate < ZStream
574     ##
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.
579     #
580     # This method is almost equivalent to the following code:
581     #
582     #   def deflate(string, level)
583     #     z = Zlib::Deflate.new(level)
584     #     dst = z.deflate(string, Zlib::FINISH)
585     #     z.close
586     #     dst
587     #   end
589     def self.deflate(data, level = Zlib::DEFAULT_COMPRESSION)
590       deflator = new level
592       zipped = deflator.deflate data, Zlib::FINISH
594       zipped
595     ensure
596       deflator.end
597     end
599     ##
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
602     # is used.
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
613       super()
615       @func_end = :deflateEnd
616       @func_reset = :deflateReset
617       @func_run = :deflate
619       err = Zlib.deflateInit2(pointer, level, Zlib::DEFLATED,
620                               window_bits, mem_level, strategy)
622       Zlib.handle_error err, message
624       ready
625     end
627     ##
628     # Same as IO.
630     def <<(data)
631       do_deflate data, Zlib::NO_FLUSH
633       self
634     end
636     ##
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.
641     #
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
649       detatch_output
650     end
652     ##
653     # Performs the deflate operation and leaves the compressed data in the
654     # output buffer
656     def do_deflate(data, flush)
657       if data.nil? then
658         run '', Zlib::FINISH
659       else
660         data = StringValue data
662         if flush != Zlib::NO_FLUSH or not data.empty? then # prevent BUF_ERROR
663           run data, flush
664         end
665       end
666     end
668     ##
669     # Finishes compressing the deflate input stream and returns the output
670     # buffer.
672     def finish
673       run '', Zlib::FINISH
675       detatch_output
676     end
678     ##
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
686       detatch_output
687     end
689     ##
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
692     # buffer.
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
702       nil
703     end
705     ##
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
717       dictionary
718     end
720   end
722   ##
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.
726   #
727   # GzipReader should be used by associating an IO, or IO-like, object.
729   class GzipFile
731     SYNC            = Zlib::ZStream::UNUSED
732     HEADER_FINISHED = Zlib::ZStream::UNUSED << 1
733     FOOTER_FINISHED = Zlib::ZStream::UNUSED << 2
735     FLAG_MULTIPART    = 0x2
736     FLAG_EXTRA        = 0x4
737     FLAG_ORIG_NAME    = 0x8
738     FLAG_COMMENT      = 0x10
739     FLAG_ENCRYPT      = 0x20
740     FLAG_UNKNOWN_MASK = 0xc0
742     EXTRAFLAG_FAST    = 0x4
743     EXTRAFLAG_SLOW    = 0x2
745     MAGIC1         = 0x1f
746     MAGIC2         = 0x8b
747     METHOD_DEFLATE = 8
749     ##
750     # Base class of errors that occur when processing GZIP files.
752     class Error < Zlib::Error; end
754     ##
755     # Raised when gzip file footer is not found. 
757     class NoFooter < Error; end
759     ##
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
765     ##
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
771     ##
772     # Accessor for the underlying ZStream
774     attr_reader :zstream # :nodoc:
776     ##
777     # See Zlib::GzipReader#wrap and Zlib::GzipWriter#wrap.
779     def self.wrap(*args)
780       obj = new(*args)
782       if block_given? then
783         begin
784           yield obj
785         ensure
786           obj.close if obj.zstream.ready?
787         end
788       end
789     end
791     def initialize
792       @comment = nil
793       @crc = 0
794       @level = nil
795       @mtime = Time.at 0
796       @orig_name = nil
797       @os_code = Zlib::OS_CODE
798     end
800     ##
801     # Closes the GzipFile object. This method calls close method of the
802     # associated IO object. Returns the associated IO object.
804     def close
805       io = finish
807       io.close if io.respond_to? :close
809       io
810     end
812     ##
813     # Same as IO
815     def closed?
816       @io.nil?
817     end
819     ##
820     # Returns comments recorded in the gzip file header, or nil if the
821     # comment is not present.
823     def comment
824       raise Error, 'closed gzip stream' if @io.nil?
826       @comment.dup
827     end
829     def end
830       return if @zstream.closing?
832       @zstream.flags |= Zlib::ZStream::CLOSING
834       begin
835         end_run
836       ensure
837         @zstream.end
838       end
839     end
841     ##
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.
846     def finish
847       self.end
849       io = @io
850       @io = nil
851       @orig_name = nil
852       @comment = nil
854       io
855     end
857     def finished?
858       @zstream.finished? and @zstream.output.empty? # HACK I think
859     end
861     def footer_finished?
862       @zstream.flags & Zlib::GzipFile::FOOTER_FINISHED ==
863         Zlib::GzipFile::FOOTER_FINISHED
864     end
866     def header_finished?
867       @zstream.flags & Zlib::GzipFile::HEADER_FINISHED ==
868         Zlib::GzipFile::HEADER_FINISHED
869     end
871     ##
872     # Returns last modification time recorded in the gzip file header.
874     def mtime
875       Time.at @mtime
876     end
878     ##
879     # Returns original filename recorded in the gzip file header, or +nil+ if
880     # original filename is not present.
882     def orig_name
883       raise Error, 'closed gzip stream' if @io.nil?
885       @orig_name.dup
886     end
888   end
890   ##
891   # Zlib::GzipReader is the class for reading a gzipped file.  GzipReader
892   # should be used an IO, or -IO-lie, object.
893   #
894   #   Zlib::GzipReader.open('hoge.gz') {|gz|
895   #     print gz.read
896   #   }
897   #   
898   #   File.open('hoge.gz') do |f|
899   #     gz = Zlib::GzipReader.new(f)
900   #     print gz.read
901   #     gz.close
902   #   end
903   #
904   # == Method Catalogue
905   #
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.
909   #
910   # - #each
911   # - #each_line
912   # - #each_byte
913   # - #gets
914   # - #getc
915   # - #lineno
916   # - #lineno=
917   # - #read
918   # - #readchar
919   # - #readline
920   # - #readlines
921   # - #ungetc
922   #
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.
928   #
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
933   #   end of file.
934   # - When Zlib::GzipReader#unused method is called after the object reaches
935   #   the end of file.
936   #
937   # The rest of the methods are adequately described in their own
938   # documentation.
940   class GzipReader < GzipFile # HACK use a buffer class
942     ##
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
946     # IO class.
947     #
948     # If the gzip file header is incorrect, raises an Zlib::GzipFile::Error
949     # exception.
951     def initialize(io)
952       @io = io
954       @zstream = Zlib::Inflate.new -Zlib::MAX_WBITS
956       @buffer = ''
958       super()
960       read_header
961     end
963     def check_footer
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
980     end
982     def end_run
983       check_footer if @zstream.finished? and not footer_finished?
984     end
986     def eof?
987       @zstream.finished? and @zstream.input_empty?
988     end
990     def pos
991       @zstream[:total_out] - @buffer.length
992     end
994     ##
995     # See Zlib::GzipReader documentation for a description.
997     def read(length = nil)
998       data = @buffer
1000       while chunk = @io.read(CHUNK) do
1001         inflated = @zstream.inflate(chunk)
1002         @crc = Zlib.crc32 inflated, @crc
1003         data << inflated
1005         break if length and data.length > length
1006       end
1008       if length then
1009         @buffer = data.slice! length..-1
1010       else
1011         @buffer = ''
1012       end
1014       check_footer if @zstream.finished? and not footer_finished?
1016       data
1017     rescue Zlib::Error => e
1018       raise GzipFile::Error, e.message
1019     end
1021     def read_header
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'
1032       end
1034       unless method == Zlib::GzipFile::METHOD_DEFLATE then
1035         raise Error, "unsupported compression method #{method}"
1036       end
1038       if flags & Zlib::GzipFile::FLAG_MULTIPART ==
1039            Zlib::GzipFile::FLAG_MULTIPART then
1040         raise Error, 'multi-part gzip file is not supported'
1041       end
1043       if flags & Zlib::GzipFile::FLAG_ENCRYPT ==
1044            Zlib::GzipFile::FLAG_ENCRYPT then
1045         raise Error, 'encrypted gzip file is not supported'
1046       end
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}"
1051       end
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
1059       else
1060         @level = Zlib::DEFAULT_COMPRESSION
1061       end
1063       if flags & Zlib::GzipFile::FLAG_EXTRA == Zlib::GzipFile::FLAG_EXTRA then
1064         length = @io.read 2
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
1074       end
1076       if flags & Zlib::GzipFile::FLAG_ORIG_NAME ==
1077            Zlib::GzipFile::FLAG_ORIG_NAME then
1078         @orig_name = ''
1080         c = @io.getc
1082         until c == 0 do
1083           @orig_name << c.chr
1084           c = @io.getc
1085         end
1086       end
1088       if flags & Zlib::GzipFile::FLAG_COMMENT ==
1089            Zlib::GzipFile::FLAG_COMMENT then
1090         @comment = ''
1092         c = @io.getc
1094         until c == 0 do
1095           @comment << c.chr
1096           c = @io.getc
1097         end
1098       end
1099     end
1101   end
1103   ##
1104   # Zlib::GzipWriter is a class for writing gzipped files.  GzipWriter should
1105   # be used with an instance of IO, or IO-like, object.
1106   #
1107   # For example:
1108   #
1109   #   Zlib::GzipWriter.open('hoge.gz') do |gz|
1110   #     gz.write 'jugemu jugemu gokou no surikire...'
1111   #   end
1112   #   
1113   #   File.open('hoge.gz', 'w') do |f|
1114   #     gz = Zlib::GzipWriter.new(f)
1115   #     gz.write 'jugemu jugemu gokou no surikire...'
1116   #     gz.close
1117   #   end
1118   #
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
1122   # file.
1124   class GzipWriter < GzipFile # HACK use a buffer class
1126     ##
1127     # Set the comment
1129     attr_writer :comment
1131     ##
1132     # Set the original name
1134     attr_writer :orig_name
1136     ##
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
1141     # class.
1143     def initialize(io, level = Zlib::DEFAULT_COMPRESSION,
1144                    strategy = Zlib::DEFAULT_STRATEGY)
1145       @io = io
1147       @zstream = Zlib::Deflate.new level, -Zlib::MAX_WBITS,
1148                                    Zlib::DEF_MEM_LEVEL, strategy
1150       @buffer = ''
1152       super()
1153     end
1155     def end_run
1156       make_header unless header_finished?
1158       @zstream.run '', Zlib::FINISH
1160       write_raw
1162       make_footer
1164       nil
1165     end
1167     ##
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>.
1173     def flush
1174       true
1175     end
1177     ##
1178     # Writes out a gzip header
1180     def make_header
1181       flags = 0
1182       extra_flags = 0
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
1193       header = [
1194         Zlib::GzipFile::MAGIC1,         # byte 0
1195         Zlib::GzipFile::MAGIC2,         # byte 1
1196         Zlib::GzipFile::METHOD_DEFLATE, # byte 2
1197         flags,                          # byte 3
1198         @mtime.to_i,                    # bytes 4-7
1199         extra_flags,                    # byte 8
1200         @os_code                        # byte 9
1201       ].pack 'CCCCVCC'
1203       @io.write header
1205       @io.write "#{@orig_name}\0" if @orig_name
1206       @io.write "#{@comment}\0" if @comment
1208       @zstream.flags |= Zlib::GzipFile::HEADER_FINISHED
1209     end
1211     ##
1212     # Writes out a gzip footer
1214     def make_footer
1215       footer = [
1216         @crc,              # bytes 0-3
1217         @zstream.total_in, # bytes 4-7
1218       ].pack 'VV'
1220       @io.write footer
1222       @zstream.flags |= Zlib::GzipFile::FOOTER_FINISHED
1223     end
1225     ##
1226     # Sets the modification time of this file
1228     def mtime=(time)
1229       if header_finished? then
1230         raise Zlib::GzipFile::Error, 'header is already written'
1231       end
1233       @mtime = Integer time
1234     end
1236     def sync?
1237       @zstream.flags & Zlib::GzipFile::SYNC == Zlib::GzipFile::SYNC
1238     end
1240     ##
1241     # Same as IO.
1243     def write(data)
1244       make_header unless header_finished?
1246       data = String data
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
1254       end
1256       write_raw
1257     end
1259     ##
1260     # Same as IO.
1262     alias << write
1264     def write_raw
1265       data = @zstream.detatch_output
1267       unless data.empty? then
1268         @io.write data
1269         @io.flush if sync? and io.respond_to :flush
1270       end
1271     end
1273   end
1275   ##
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,
1278   # dup) itself.
1280   class Inflate < ZStream
1282     ##
1283     # Decompresses +string+. Raises a Zlib::NeedDict exception if a preset
1284     # dictionary is needed for decompression.
1285     #
1286     # This method is almost equivalent to the following code:
1287     #
1288     #   def inflate(string)
1289     #     zstream = Zlib::Inflate.new
1290     #     buf = zstream.inflate(string)
1291     #     zstream.finish
1292     #     zstream.close
1293     #     buf
1294     #   end
1296     def self.inflate(data)
1297       inflator = new
1299       unzipped = inflator.inflate data
1301       unzipped
1302     ensure
1303       inflator.end
1304     end
1306     ##
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)
1311       super()
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
1321       ready
1322     end
1324     ##
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.
1329     def <<(string)
1330       string = StringValue string unless string.nil?
1332       if finished? then
1333         unless string.nil? then
1334           @input ||= ''
1335           @input << string
1336         end
1337       else
1338         run string, Zlib::SYNC_FLUSH
1339       end
1340     end
1342     ##
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.
1347     #
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>)
1352     def inflate(data)
1353       data = Type.coerce_to data, String, :to_str unless data.nil?
1355       if finished? then
1356         if data.nil? then
1357           unzipped = detatch_output
1358         else
1359           @input ||= ''
1360           @input << data
1362           unzipped = ''
1363         end
1364       else
1365         if data.nil? then
1366           run '', Zlib::FINISH
1367         elsif not data.empty? then
1368           run data, Zlib::SYNC_FLUSH
1369         end
1371         unzipped = detatch_output
1373         if finished? and not @input.nil? then
1374           expand_output
1375         end
1376       end
1378       unzipped
1379     end
1381     ##
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
1393       dictionary
1394     end
1396   end
1398   ##
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)
1405   end
1407   ##
1408   # Returns the table for calculating CRC checksum as an array.
1410   def self.crc_table
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
1413     end
1414   end
1416   ##
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)
1423   end
1425   ##
1426   # Generates a checksum using function +type+
1428   def self.do_checksum(string, vsum, type)
1429     if vsum
1430       raise RangeError if vsum >= (2 ** 128)
1431       raise "Explain why you did this: email ephoenix@engineyard.com" if vsum < 0
1432       sum = vsum
1433     elsif string.nil?
1434       sum = 0
1435     else
1436       sum = send(type, 0, nil, 0)
1437     end
1439     send(type, sum, string, string ? string.size : 0)
1440   end
1442   ##
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?
1450     klass = case error
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
1458             else
1459               message = "unknown zlib error #{error}: #{message}"
1460               Zlib::Error
1461             end
1463     raise klass, message
1464   end