archive-zip 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/HACKING +25 -42
  2. data/NEWS +25 -0
  3. data/README +2 -2
  4. data/Rakefile +202 -0
  5. data/TODO +5 -0
  6. data/default.mspec +8 -0
  7. data/lib/archive/support/binary_stringio.rb +23 -0
  8. data/lib/archive/support/integer.rb +13 -0
  9. data/lib/archive/support/io-like.rb +3 -1
  10. data/lib/archive/support/ioextensions.rb +16 -0
  11. data/lib/archive/support/iowindow.rb +10 -18
  12. data/lib/archive/support/time.rb +2 -0
  13. data/lib/archive/support/zlib.rb +298 -71
  14. data/lib/archive/zip.rb +161 -139
  15. data/lib/archive/zip/codec.rb +2 -0
  16. data/lib/archive/zip/codec/deflate.rb +59 -11
  17. data/lib/archive/zip/codec/null_encryption.rb +75 -14
  18. data/lib/archive/zip/codec/store.rb +75 -26
  19. data/lib/archive/zip/codec/traditional_encryption.rb +146 -35
  20. data/lib/archive/zip/data_descriptor.rb +6 -4
  21. data/lib/archive/zip/entry.rb +184 -132
  22. data/lib/archive/zip/error.rb +2 -0
  23. data/lib/archive/zip/extra_field.rb +20 -6
  24. data/lib/archive/zip/extra_field/extended_timestamp.rb +141 -60
  25. data/lib/archive/zip/extra_field/raw.rb +70 -12
  26. data/lib/archive/zip/extra_field/unix.rb +58 -16
  27. data/lib/archive/zip/version.rb +6 -0
  28. data/spec/archive/zip/codec/deflate/compress/checksum_spec.rb +42 -0
  29. data/spec/archive/zip/codec/deflate/compress/close_spec.rb +44 -0
  30. data/spec/archive/zip/codec/deflate/compress/crc32_spec.rb +21 -0
  31. data/spec/archive/zip/codec/deflate/compress/data_descriptor_spec.rb +67 -0
  32. data/spec/archive/zip/codec/deflate/compress/new_spec.rb +37 -0
  33. data/spec/archive/zip/codec/deflate/compress/open_spec.rb +46 -0
  34. data/spec/archive/zip/codec/deflate/compress/write_spec.rb +109 -0
  35. data/spec/archive/zip/codec/deflate/decompress/checksum_spec.rb +18 -0
  36. data/spec/archive/zip/codec/deflate/decompress/close_spec.rb +33 -0
  37. data/spec/archive/zip/codec/deflate/decompress/crc32_spec.rb +18 -0
  38. data/spec/archive/zip/codec/deflate/decompress/data_descriptor_spec.rb +67 -0
  39. data/spec/archive/zip/codec/deflate/decompress/new_spec.rb +14 -0
  40. data/spec/archive/zip/codec/deflate/decompress/open_spec.rb +27 -0
  41. data/spec/archive/zip/codec/deflate/fixtures/classes.rb +25 -0
  42. data/spec/archive/zip/codec/deflate/fixtures/compressed_file.bin +1 -0
  43. data/spec/archive/zip/codec/deflate/fixtures/compressed_file_nocomp.bin +0 -0
  44. data/spec/archive/zip/codec/deflate/fixtures/raw_file.txt +10 -0
  45. data/spec/archive/zip/codec/null_encryption/decrypt/close_spec.rb +33 -0
  46. data/spec/archive/zip/codec/null_encryption/decrypt/new_spec.rb +14 -0
  47. data/spec/archive/zip/codec/null_encryption/decrypt/open_spec.rb +27 -0
  48. data/spec/archive/zip/codec/null_encryption/decrypt/read_spec.rb +24 -0
  49. data/spec/archive/zip/codec/null_encryption/decrypt/rewind_spec.rb +25 -0
  50. data/spec/archive/zip/codec/null_encryption/decrypt/seek_spec.rb +57 -0
  51. data/spec/archive/zip/codec/null_encryption/decrypt/tell_spec.rb +21 -0
  52. data/spec/archive/zip/codec/null_encryption/encrypt/close_spec.rb +33 -0
  53. data/spec/archive/zip/codec/null_encryption/encrypt/new_spec.rb +14 -0
  54. data/spec/archive/zip/codec/null_encryption/encrypt/open_spec.rb +27 -0
  55. data/spec/archive/zip/codec/null_encryption/encrypt/rewind_spec.rb +26 -0
  56. data/spec/archive/zip/codec/null_encryption/encrypt/seek_spec.rb +50 -0
  57. data/spec/archive/zip/codec/null_encryption/encrypt/tell_spec.rb +29 -0
  58. data/spec/archive/zip/codec/null_encryption/encrypt/write_spec.rb +29 -0
  59. data/spec/archive/zip/codec/null_encryption/fixtures/classes.rb +12 -0
  60. data/spec/archive/zip/codec/null_encryption/fixtures/raw_file.txt +10 -0
  61. data/spec/archive/zip/codec/store/compress/close_spec.rb +33 -0
  62. data/spec/archive/zip/codec/store/compress/data_descriptor_spec.rb +68 -0
  63. data/spec/archive/zip/codec/store/compress/new_spec.rb +14 -0
  64. data/spec/archive/zip/codec/store/compress/open_spec.rb +27 -0
  65. data/spec/archive/zip/codec/store/compress/rewind_spec.rb +26 -0
  66. data/spec/archive/zip/codec/store/compress/seek_spec.rb +50 -0
  67. data/spec/archive/zip/codec/store/compress/tell_spec.rb +29 -0
  68. data/spec/archive/zip/codec/store/compress/write_spec.rb +29 -0
  69. data/spec/archive/zip/codec/store/decompress/close_spec.rb +33 -0
  70. data/spec/archive/zip/codec/store/decompress/data_descriptor_spec.rb +68 -0
  71. data/spec/archive/zip/codec/store/decompress/new_spec.rb +14 -0
  72. data/spec/archive/zip/codec/store/decompress/open_spec.rb +27 -0
  73. data/spec/archive/zip/codec/store/decompress/read_spec.rb +24 -0
  74. data/spec/archive/zip/codec/store/decompress/rewind_spec.rb +25 -0
  75. data/spec/archive/zip/codec/store/decompress/seek_spec.rb +57 -0
  76. data/spec/archive/zip/codec/store/decompress/tell_spec.rb +21 -0
  77. data/spec/archive/zip/codec/store/fixtures/classes.rb +12 -0
  78. data/spec/archive/zip/codec/store/fixtures/raw_file.txt +10 -0
  79. data/spec/archive/zip/codec/traditional_encryption/decrypt/close_spec.rb +64 -0
  80. data/spec/archive/zip/codec/traditional_encryption/decrypt/new_spec.rb +18 -0
  81. data/spec/archive/zip/codec/traditional_encryption/decrypt/open_spec.rb +39 -0
  82. data/spec/archive/zip/codec/traditional_encryption/decrypt/read_spec.rb +126 -0
  83. data/spec/archive/zip/codec/traditional_encryption/decrypt/rewind_spec.rb +38 -0
  84. data/spec/archive/zip/codec/traditional_encryption/decrypt/seek_spec.rb +82 -0
  85. data/spec/archive/zip/codec/traditional_encryption/decrypt/tell_spec.rb +25 -0
  86. data/spec/archive/zip/codec/traditional_encryption/encrypt/close_spec.rb +64 -0
  87. data/spec/archive/zip/codec/traditional_encryption/encrypt/new_spec.rb +18 -0
  88. data/spec/archive/zip/codec/traditional_encryption/encrypt/open_spec.rb +39 -0
  89. data/spec/archive/zip/codec/traditional_encryption/encrypt/rewind_spec.rb +41 -0
  90. data/spec/archive/zip/codec/traditional_encryption/encrypt/seek_spec.rb +75 -0
  91. data/spec/archive/zip/codec/traditional_encryption/encrypt/tell_spec.rb +42 -0
  92. data/spec/archive/zip/codec/traditional_encryption/encrypt/write_spec.rb +127 -0
  93. data/spec/archive/zip/codec/traditional_encryption/fixtures/classes.rb +27 -0
  94. data/spec/archive/zip/codec/traditional_encryption/fixtures/encrypted_file.bin +0 -0
  95. data/spec/archive/zip/codec/traditional_encryption/fixtures/raw_file.txt +10 -0
  96. data/spec/binary_stringio/new_spec.rb +34 -0
  97. data/spec/binary_stringio/set_encoding_spec.rb +14 -0
  98. data/spec/ioextensions/read_exactly_spec.rb +50 -0
  99. data/spec/zlib/fixtures/classes.rb +65 -0
  100. data/spec/zlib/fixtures/compressed_file.bin +1 -0
  101. data/spec/zlib/fixtures/compressed_file_gzip.bin +0 -0
  102. data/spec/zlib/fixtures/compressed_file_huffman.bin +2 -0
  103. data/spec/zlib/fixtures/compressed_file_minmem.bin +0 -0
  104. data/spec/zlib/fixtures/compressed_file_minwin.bin +1 -0
  105. data/spec/zlib/fixtures/compressed_file_nocomp.bin +0 -0
  106. data/spec/zlib/fixtures/compressed_file_raw.bin +1 -0
  107. data/spec/zlib/fixtures/raw_file.txt +10 -0
  108. data/spec/zlib/zreader/checksum_spec.rb +40 -0
  109. data/spec/zlib/zreader/close_spec.rb +14 -0
  110. data/spec/zlib/zreader/compressed_size_spec.rb +18 -0
  111. data/spec/zlib/zreader/new_spec.rb +41 -0
  112. data/spec/zlib/zreader/open_spec.rb +49 -0
  113. data/spec/zlib/zreader/read_spec.rb +47 -0
  114. data/spec/zlib/zreader/rewind_spec.rb +23 -0
  115. data/spec/zlib/zreader/seek_spec.rb +55 -0
  116. data/spec/zlib/zreader/tell_spec.rb +21 -0
  117. data/spec/zlib/zreader/uncompressed_size_spec.rb +18 -0
  118. data/spec/zlib/zwriter/checksum_spec.rb +41 -0
  119. data/spec/zlib/zwriter/close_spec.rb +14 -0
  120. data/spec/zlib/zwriter/compressed_size_spec.rb +19 -0
  121. data/spec/zlib/zwriter/new_spec.rb +64 -0
  122. data/spec/zlib/zwriter/open_spec.rb +68 -0
  123. data/spec/zlib/zwriter/rewind_spec.rb +26 -0
  124. data/spec/zlib/zwriter/seek_spec.rb +54 -0
  125. data/spec/zlib/zwriter/tell_spec.rb +29 -0
  126. data/spec/zlib/zwriter/uncompressed_size_spec.rb +19 -0
  127. data/spec/zlib/zwriter/write_spec.rb +28 -0
  128. data/spec_helper.rb +49 -0
  129. metadata +296 -74
  130. data/MANIFEST +0 -27
  131. data/lib/archive/support/io.rb +0 -14
  132. data/lib/archive/support/stringio.rb +0 -22
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  class Time
2
4
  # Returns a DOSTime representing this time object as a DOS date-time
3
5
  # structure. Times are bracketed by the limits of the ability of the DOS
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'zlib'
2
4
 
3
5
  require 'archive/support/io-like'
@@ -7,6 +9,14 @@ module Zlib # :nodoc:
7
9
  MAX_WBITS = Deflate::MAX_WBITS
8
10
  end
9
11
 
12
+ # A deflate strategy which limits match distances to 1, also known as
13
+ # run-length encoding.
14
+ RLE = 3
15
+
16
+ # A deflate strategy which does not use dynamic Huffman codes, allowing for a
17
+ # simpler decoder to be used to inflate.
18
+ FIXED = 4
19
+
10
20
  # Zlib::ZWriter is a writable, IO-like object (includes IO::Like) which wraps
11
21
  # other writable, IO-like objects in order to facilitate writing data to those
12
22
  # objects using the deflate method of compression.
@@ -18,8 +28,8 @@ module Zlib # :nodoc:
18
28
  # guaranteed to be called after the block completes.
19
29
  #
20
30
  # Equivalent to #new if no block is given.
21
- def self.open(io, level = Zlib::DEFAULT_COMPRESSION, window_bits = nil, mem_level = nil, strategy = nil)
22
- zw = new(io, level, window_bits, mem_level, strategy)
31
+ def self.open(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil)
32
+ zw = new(delegate, level, window_bits, mem_level, strategy)
23
33
  return zw unless block_given?
24
34
 
25
35
  begin
@@ -29,28 +39,112 @@ module Zlib # :nodoc:
29
39
  end
30
40
  end
31
41
 
32
- # Creates a new instance of this class. _io_ must respond to the _write_
33
- # method as an instance of IO would. _level_, _window_bits_, _mem_level_,
34
- # and _strategy_ are all passed directly to Zlib::Deflate.new(). See the
35
- # documentation of that method for their meanings.
42
+ # Creates a new instance of this class. _delegate_ must respond to the
43
+ # _write_ method as an instance of IO would. _level_, _window_bits_,
44
+ # _mem_level_, and _strategy_ are all passed directly to
45
+ # Zlib::Deflate.new().
46
+ #
47
+ # <b>
48
+ # The following descriptions of _level_, _window_bits_, _mem_level_, and
49
+ # _strategy_ are based upon or pulled largely verbatim from descriptions
50
+ # found in zlib.h version 1.2.3 with changes made to account for different
51
+ # parameter names and to improve readability. Some of the statements
52
+ # concerning default settings or value ranges may not be accurate depending
53
+ # on the version of the zlib library used by a given Ruby interpreter.
54
+ # </b>
55
+ #
56
+ # The _level_ parameter must be +nil+, Zlib::DEFAULT_COMPRESSION, or between
57
+ # <tt>0</tt> and <tt>9</tt>: <tt>1</tt> gives best speed, <tt>9</tt> gives
58
+ # best compression, <tt>0</tt> gives no compression at all (the input data
59
+ # is simply copied a block at a time). Zlib::DEFAULT_COMPRESSION requests a
60
+ # default compromise between speed and compression (currently equivalent to
61
+ # level <tt>6</tt>). If unspecified or +nil+, _level_ defaults to
62
+ # Zlib::DEFAULT_COMPRESSION.
63
+ #
64
+ # The _window_bits_ parameter specifies the size of the history buffer, the
65
+ # format of the compressed stream, and the kind of checksum returned by the
66
+ # checksum method. The size of the history buffer is specified by setting
67
+ # the value of _window_bits_ in the range of <tt>8</tt>..<tt>15</tt>,
68
+ # inclusive. A value of <tt>8</tt> indicates a small window which reduces
69
+ # memory usage but lowers the compression ratio while a value of <tt>15</tt>
70
+ # indicates a larger window which increases memory usage but raises the
71
+ # compression ratio. Modification of this base value for _window_bits_ as
72
+ # noted below dictates what kind of compressed stream and checksum will be
73
+ # produced <b>while preserving the setting for the history buffer</b>.
74
+ #
75
+ # If nothing else is done to the base value of _window_bits_, a zlib stream
76
+ # is to be produced with an appropriate header and trailer. In this case
77
+ # the checksum method of this object will be an adler32.
78
+ #
79
+ # Adding <tt>16</tt> to the base value of _window_bits_ indicates that a
80
+ # gzip stream is to be produced with an appropriate header and trailer. The
81
+ # gzip header will have no file name, no extra data, no comment, no
82
+ # modification time (set to zero), no header crc, and the operating system
83
+ # will be set to <tt>255</tt> (unknown). In this case the checksum
84
+ # attribute of this object will be a crc32.
85
+ #
86
+ # Finally, negating the base value of _window_bits_ indicates that a raw
87
+ # zlib stream is to be produced without any header or trailer. In this case
88
+ # the checksum method of this object will always return <tt>1</tt>. This is
89
+ # for use with other formats that use the deflate compressed data format
90
+ # such as zip. Such formats should provide their own check values.
91
+ #
92
+ # If unspecified or +nil+, _window_bits_ defaults to <tt>15</tt>.
93
+ #
94
+ # The _mem_level_ parameter specifies how much memory should be allocated
95
+ # for the internal compression state. A value of <tt>1</tt> uses minimum
96
+ # memory but is slow and reduces compression ratio; a value of <tt>9</tt>
97
+ # uses maximum memory for optimal speed. The default value is <tt>8</tt> if
98
+ # unspecified or +nil+.
99
+ #
100
+ # The _strategy_ parameter is used to tune the compression algorithm. It
101
+ # only affects the compression ratio but not the correctness of the
102
+ # compressed output even if it is not set appropriately. The default value
103
+ # is Zlib::DEFAULT_STRATEGY if unspecified or +nil+.
104
+ #
105
+ # Use the value Zlib::DEFAULT_STRATEGY for normal data, Zlib::FILTERED for
106
+ # data produced by a filter (or predictor), Zlib::HUFFMAN_ONLY to force
107
+ # Huffman encoding only (no string match), Zlib::RLE to limit match
108
+ # distances to 1 (run-length encoding), or Zlib::FIXED to simplify decoder
109
+ # requirements.
110
+ #
111
+ # The effect of Zlib::FILTERED is to force more Huffman coding and less
112
+ # string matching; it is somewhat intermediate between
113
+ # Zlib::DEFAULT_STRATEGY and Zlib::HUFFMAN_ONLY. Filtered data consists
114
+ # mostly of small values with a somewhat random distribution. In this case,
115
+ # the compression algorithm is tuned to compress them better.
116
+ #
117
+ # Zlib::RLE is designed to be almost as fast as Zlib::HUFFMAN_ONLY, but give
118
+ # better compression for PNG image data.
119
+ #
120
+ # Zlib::FIXED prevents the use of dynamic Huffman codes, allowing for a
121
+ # simpler decoder for special applications.
122
+ #
123
+ # This class has extremely limited seek capabilities. It is possible to
124
+ # seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
125
+ # As a result, the _pos_ and _tell_ methods also work as expected.
126
+ #
127
+ # If _delegate_ also responds to _rewind_, then the _rewind_ method of this
128
+ # class can be used to reset the whole stream back to the beginning. Using
129
+ # _seek_ of this class to seek directly to offset <tt>0</tt> using
130
+ # <tt>IO::SEEK_SET</tt> for whence will also work in this case.
36
131
  #
37
132
  # <b>NOTE:</b> Due to limitations in Ruby's finalization capabilities, the
38
133
  # #close method is _not_ automatically called when this object is garbage
39
134
  # collected. Make sure to call #close when finished with this object.
40
- def initialize(io, level = Zlib::DEFAULT_COMPRESSION, window_bits = nil, mem_level = nil, strategy = nil)
41
- @delegate = io
42
- @deflater = Zlib::Deflate.new(level, window_bits, mem_level, strategy)
135
+ def initialize(delegate, level = nil, window_bits = nil, mem_level = nil, strategy = nil)
136
+ @delegate = delegate
137
+ @level = level
138
+ @window_bits = window_bits
139
+ @mem_level = mem_level
140
+ @strategy = strategy
141
+ @deflater = Zlib::Deflate.new(@level, @window_bits, @mem_level, @strategy)
43
142
  @deflate_buffer = ''
44
- @crc32 = 0
143
+ @checksum = nil
144
+ @compressed_size = nil
145
+ @uncompressed_size = nil
45
146
  end
46
147
 
47
- # The CRC32 checksum of the uncompressed data written using this object.
48
- #
49
- # <b>NOTE:</b> Anything still in the internal write buffer has not been
50
- # processed, so calling #flush prior to examining this attribute may be
51
- # necessary for an accurate computation.
52
- attr_reader :crc32
53
-
54
148
  protected
55
149
 
56
150
  # The delegate object to which compressed data is written.
@@ -58,49 +152,100 @@ module Zlib # :nodoc:
58
152
 
59
153
  public
60
154
 
155
+ # Returns the checksum computed over the data written to this stream so far.
156
+ #
157
+ # <b>NOTE:</b> Refer to the documentation of #new concerning _window_bits_
158
+ # to learn what kind of checksum will be returned.
159
+ #
160
+ # <b>NOTE:</b> Anything still in the internal write buffer has not been
161
+ # processed, so calling #flush prior to calling this method may be necessary
162
+ # for an accurate checksum.
163
+ def checksum
164
+ @deflater.closed? ? @checksum : @deflater.adler
165
+ end
166
+
61
167
  # Closes the writer by finishing the compressed data and flushing it to the
62
168
  # delegate.
63
169
  #
64
170
  # Raises IOError if called more than once.
65
171
  def close
172
+ flush()
173
+ @deflate_buffer << @deflater.finish unless @deflater.finished?
174
+ begin
175
+ until @deflate_buffer.empty? do
176
+ @deflate_buffer.slice!(0, delegate.write(@deflate_buffer))
177
+ end
178
+ rescue Errno::EAGAIN, Errno::EINTR
179
+ retry if write_ready?
180
+ end
181
+ @checksum = @deflater.adler
182
+ @compressed_size = @deflater.total_out
183
+ @uncompressed_size = @deflater.total_in
184
+ @deflater.close
66
185
  super()
67
- delegate.write(@deflater.finish)
68
186
  nil
69
187
  end
70
188
 
71
189
  # Returns the number of bytes of compressed data produced so far.
72
190
  #
73
- # <b>NOTE:</b> Anything still in the internal write buffer has not been
74
- # processed, so calling #flush prior to calling this method may be necessary
75
- # for an accurate count.
191
+ # <b>NOTE:</b> This value is only updated when both the internal write
192
+ # buffer is flushed and there is enough data to produce a compressed block.
193
+ # It does not necessarily reflect the amount of data written to the
194
+ # delegate until this stream is closed however. Until then the only
195
+ # guarantee is that the value will be greater than or equal to <tt>0</tt>.
76
196
  def compressed_size
77
- @deflater.total_out
197
+ @deflater.closed? ? @compressed_size : @deflater.total_out
78
198
  end
79
199
 
80
200
  # Returns the number of bytes sent to be compressed so far.
81
201
  #
82
- # <b>NOTE:</b> Anything still in the internal write buffer has not been
83
- # processed, so calling #flush prior to calling this method may be necessary
84
- # for an accurate count.
202
+ # <b>NOTE:</b> This value is only updated when the internal write buffer is
203
+ # flushed.
85
204
  def uncompressed_size
86
- @deflater.total_in
205
+ @deflater.closed? ? @uncompressed_size : @deflater.total_in
87
206
  end
88
207
 
89
208
  private
90
209
 
210
+ # Allows resetting this object and the delegate object back to the beginning
211
+ # of the stream or reporting the current position in the stream.
212
+ #
213
+ # Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is either
214
+ # IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_ is
215
+ # IO::SEEK_SEK and the delegate object does not respond to the _rewind_
216
+ # method.
217
+ def unbuffered_seek(offset, whence = IO::SEEK_SET)
218
+ unless offset == 0 &&
219
+ ((whence == IO::SEEK_SET && delegate.respond_to?(:rewind)) ||
220
+ whence == IO::SEEK_CUR) then
221
+ raise Errno::EINVAL
222
+ end
223
+
224
+ case whence
225
+ when IO::SEEK_SET
226
+ delegate.rewind
227
+ @deflater.finish
228
+ @deflater.close
229
+ @deflater = Zlib::Deflate.new(
230
+ @level, @window_bits, @mem_level, @strategy
231
+ )
232
+ @deflate_buffer = ''
233
+ 0
234
+ when IO::SEEK_CUR
235
+ @deflater.total_in
236
+ end
237
+ end
238
+
91
239
  def unbuffered_write(string)
240
+ # First try to write out the contents of the deflate buffer because if
241
+ # that raises a failure we can let that pass up the call stack without
242
+ # having polluted the deflater instance.
92
243
  until @deflate_buffer.empty? do
93
244
  @deflate_buffer.slice!(0, delegate.write(@deflate_buffer))
94
245
  end
246
+ # At this point we can deflate the given string into a new buffer and
247
+ # behave as if it was written.
95
248
  @deflate_buffer = @deflater.deflate(string)
96
-
97
- begin
98
- @deflate_buffer.slice!(0, delegate.write(@deflate_buffer))
99
- rescue Errno::EINTR, Errno::EAGAIN
100
- # Ignore this because everything is in the deflate buffer and will be
101
- # attempted again the next time this method is called.
102
- end
103
- @crc32 = Zlib.crc32(string, @crc32)
104
249
  string.length
105
250
  end
106
251
  end
@@ -120,8 +265,8 @@ module Zlib # :nodoc:
120
265
  # guaranteed to be called after the block completes.
121
266
  #
122
267
  # Equivalent to #new if no block is given.
123
- def self.open(io, window_bits = nil)
124
- zr = new(io, window_bits)
268
+ def self.open(delegate, window_bits = nil)
269
+ zr = new(delegate, window_bits)
125
270
  return zr unless block_given?
126
271
 
127
272
  begin
@@ -131,31 +276,82 @@ module Zlib # :nodoc:
131
276
  end
132
277
  end
133
278
 
134
- # Creates a new instance of this class. _io_ must respond to the _read_
135
- # method as an IO instance would. _window_bits_ is passed directly to
136
- # Zlib::Inflate.new(). See the documentation of that method for its
137
- # meaning. If _io_ also responds to _rewind_, then the _rewind_ method of
138
- # this class can be used to reset the whole stream back to the beginning.
279
+ # Creates a new instance of this class. _delegate_ must respond to the
280
+ # _read_ method as an IO instance would. _window_bits_ is passed directly
281
+ # to Zlib::Inflate.new().
282
+ #
283
+ # <b>
284
+ # The following description of _window_bits_ is based on the description
285
+ # found in zlib.h version 1.2.3. Some of the statements concerning default
286
+ # settings or value ranges may not be accurate depending on the version of
287
+ # the zlib library used by a given Ruby interpreter.
288
+ # </b>
289
+ #
290
+ # The _window_bits_ parameter specifies the size of the history buffer, the
291
+ # format of the compressed stream, and the kind of checksum returned by the
292
+ # checksum method. The size of the history buffer is specified by setting
293
+ # the value of _window_bits_ in the range of <tt>8</tt>..<tt>15</tt>,
294
+ # inclusive. It must be at least as large as the setting used to create the
295
+ # stream or a Zlib::DataError will be raised. Modification of this base
296
+ # value for _window_bits_ as noted below dictates what kind of compressed
297
+ # stream is expected and what kind of checksum will be produced <b>while
298
+ # preserving the setting for the history buffer</b>.
299
+ #
300
+ # If nothing else is done to the base value of _window_bits_, a zlib stream
301
+ # is expected with an appropriate header and trailer. In this case the
302
+ # checksum method of this object will be an adler32.
303
+ #
304
+ # Adding <tt>16</tt> to the base value of _window_bits_ indicates that a
305
+ # gzip stream is expected with an appropriate header and trailer. In this
306
+ # case the checksum method of this object will be a crc32.
307
+ #
308
+ # Adding <tt>32</tt> to the base value of _window_bits_ indicates that an
309
+ # automatic detection of the stream format should be made based on the
310
+ # header in the stream. In this case the checksum method of this object
311
+ # will depend on whether a zlib or a gzip stream is detected.
312
+ #
313
+ # Finally, negating the base value of _window_bits_ indicates that a raw
314
+ # zlib stream is expected without any header or trailer. In this case the
315
+ # checksum method of this object will always return <tt>1</tt>. This is for
316
+ # use with other formats that use the deflate compressed data format such as
317
+ # zip. Such formats should provide their own check values.
318
+ #
319
+ # If unspecified or +nil+, _window_bits_ defaults to <tt>15</tt>.
320
+ #
321
+ # In all cases, Zlib::DataError is raised if the wrong stream format is
322
+ # found <b>when reading</b>.
323
+ #
324
+ # This class has extremely limited seek capabilities. It is possible to
325
+ # seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
326
+ # As a result, the _pos_ and _tell_ methods also work as expected.
327
+ #
328
+ # Due to certain optimizations within IO::Like#seek and if there is data in
329
+ # the read buffer, the _seek_ method can be used to seek forward from the
330
+ # current stream position up to the end of the buffer. Unless it is known
331
+ # definitively how much data is in the buffer, it is best to avoid relying
332
+ # on this behavior.
333
+ #
334
+ # If _delegate_ also responds to _rewind_, then the _rewind_ method of this
335
+ # class can be used to reset the whole stream back to the beginning. Using
336
+ # _seek_ of this class to seek directly to offset <tt>0</tt> using
337
+ # <tt>IO::SEEK_SET</tt> for whence will also work in this case.
338
+ #
339
+ # Any other seeking attempts, will raise Errno::EINVAL exceptions.
139
340
  #
140
341
  # <b>NOTE:</b> Due to limitations in Ruby's finalization capabilities, the
141
342
  # #close method is _not_ automatically called when this object is garbage
142
343
  # collected. Make sure to call #close when finished with this object.
143
- def initialize(io, window_bits = nil)
144
- @delegate = io
344
+ def initialize(delegate, window_bits = nil)
345
+ @delegate = delegate
145
346
  @delegate_read_size = DEFAULT_DELEGATE_READ_SIZE
146
347
  @window_bits = window_bits
147
348
  @inflater = Zlib::Inflate.new(@window_bits)
148
- @crc32 = 0
149
- @decompress_buffer = ''
349
+ @inflate_buffer = ''
350
+ @checksum = nil
351
+ @compressed_size = nil
352
+ @uncompressed_size = nil
150
353
  end
151
354
 
152
- # The CRC32 checksum of the uncompressed data read using this object.
153
- #
154
- # <b>NOTE:</b> The contents of the internal read buffer are immediately
155
- # processed any time the buffer is filled, so this count is only accurate if
156
- # all data has been read out of this object.
157
- attr_reader :crc32
158
-
159
355
  # The number of bytes to read from the delegate object each time the
160
356
  # internal read buffer is filled.
161
357
  attr_accessor :delegate_read_size
@@ -167,57 +363,88 @@ module Zlib # :nodoc:
167
363
 
168
364
  public
169
365
 
366
+ # Returns the checksum computed over the data read from this stream.
367
+ #
368
+ # <b>NOTE:</b> Refer to the documentation of #new concerning _window_bits_
369
+ # to learn what kind of checksum will be returned.
370
+ #
371
+ # <b>NOTE:</b> The contents of the internal read buffer are immediately
372
+ # processed any time the internal buffer is filled, so this checksum is only
373
+ # accurate if all data has been read out of this object.
374
+ def checksum
375
+ @inflater.closed? ? @checksum : @inflater.adler
376
+ end
377
+
170
378
  # Closes the reader.
171
379
  #
172
380
  # Raises IOError if called more than once.
173
381
  def close
174
382
  super()
383
+ @checksum = @inflater.adler
384
+ @compressed_size = @inflater.total_in
385
+ @uncompressed_size = @inflater.total_out
175
386
  @inflater.close
176
387
  nil
177
388
  end
178
389
 
179
- # Returns the number of bytes sent to be decompressed so far.
390
+ # Returns the number of bytes sent to be compressed so far.
391
+ #
392
+ # <b>NOTE:</b> This value is updated whenever the internal read buffer needs
393
+ # to be filled, not when data is read out of this stream.
180
394
  def compressed_size
181
- @inflater.total_in
395
+ @inflater.closed? ? @compressed_size : @inflater.total_in
182
396
  end
183
397
 
184
398
  # Returns the number of bytes of decompressed data produced so far.
399
+ #
400
+ # <b>NOTE:</b> This value is updated whenever the internal read buffer needs
401
+ # to be filled, not when data is read out of this stream.
185
402
  def uncompressed_size
186
- @inflater.total_out
403
+ @inflater.closed? ? @uncompressed_size : @inflater.total_out
187
404
  end
188
405
 
189
406
  private
190
407
 
191
408
  def unbuffered_read(length)
192
- if @decompress_buffer.empty? && @inflater.finished? then
409
+ if @inflate_buffer.empty? && @inflater.finished? then
193
410
  raise EOFError, 'end of file reached'
194
411
  end
195
412
 
196
413
  begin
197
- while @decompress_buffer.length < length && ! @inflater.finished? do
198
- @decompress_buffer <<
414
+ while @inflate_buffer.length < length && ! @inflater.finished? do
415
+ @inflate_buffer <<
199
416
  @inflater.inflate(delegate.read(@delegate_read_size))
200
417
  end
201
418
  rescue Errno::EINTR, Errno::EAGAIN
202
- raise if @decompress_buffer.empty?
419
+ raise if @inflate_buffer.empty?
203
420
  end
204
- buffer = @decompress_buffer.slice!(0, length)
205
- @crc32 = Zlib.crc32(buffer, @crc32)
206
- buffer
421
+ @inflate_buffer.slice!(0, length)
207
422
  end
208
423
 
424
+ # Allows resetting this object and the delegate object back to the beginning
425
+ # of the stream or reporting the current position in the stream.
426
+ #
427
+ # Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is either
428
+ # IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_ is
429
+ # IO::SEEK_SEK and the delegate object does not respond to the _rewind_
430
+ # method.
209
431
  def unbuffered_seek(offset, whence = IO::SEEK_SET)
210
- unless offset == 0 && whence == IO::SEEK_SET then
211
- raise Errno::EINVAL, 'Invalid argument'
432
+ unless offset == 0 &&
433
+ ((whence == IO::SEEK_SET && delegate.respond_to?(:rewind)) ||
434
+ whence == IO::SEEK_CUR) then
435
+ raise Errno::EINVAL
212
436
  end
213
- unless delegate.respond_to?(:rewind) then
214
- raise Errno::ESPIPE, 'Illegal seek'
437
+
438
+ case whence
439
+ when IO::SEEK_SET
440
+ delegate.rewind
441
+ @inflater.close
442
+ @inflater = Zlib::Inflate.new(@window_bits)
443
+ @inflate_buffer = ''
444
+ 0
445
+ when IO::SEEK_CUR
446
+ @inflater.total_out - @inflate_buffer.length
215
447
  end
216
- delegate.rewind
217
- @inflater.close
218
- @inflater = Zlib::Inflate.new(@window_bits)
219
- @crc32 = 0
220
- @decompress_buffer = ''
221
448
  end
222
449
  end
223
450
  end