zliby 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/CHANGES +5 -0
  2. data/LICENSE +26 -0
  3. data/README +33 -0
  4. data/TODO +6 -0
  5. data/bin/zliber +7 -0
  6. data/lib/zliby.rb +624 -0
  7. data/specs/adler32_spec.rb +46 -0
  8. data/specs/crc32_spec.rb +52 -0
  9. data/specs/crc_table_spec.rb +11 -0
  10. data/specs/deflate/append_spec.rb +2 -0
  11. data/specs/deflate/deflate_spec.rb +49 -0
  12. data/specs/deflate/flush_spec.rb +2 -0
  13. data/specs/deflate/initialize_copy_spec.rb +2 -0
  14. data/specs/deflate/new_spec.rb +2 -0
  15. data/specs/deflate/params_spec.rb +21 -0
  16. data/specs/deflate/set_dictionary_spec.rb +14 -0
  17. data/specs/gzipfile/close_spec.rb +23 -0
  18. data/specs/gzipfile/closed_spec.rb +18 -0
  19. data/specs/gzipfile/comment_spec.rb +28 -0
  20. data/specs/gzipfile/crc_spec.rb +2 -0
  21. data/specs/gzipfile/finish_spec.rb +2 -0
  22. data/specs/gzipfile/level_spec.rb +2 -0
  23. data/specs/gzipfile/mtime_spec.rb +2 -0
  24. data/specs/gzipfile/orig_name_spec.rb +28 -0
  25. data/specs/gzipfile/os_code_spec.rb +2 -0
  26. data/specs/gzipfile/sync_spec.rb +2 -0
  27. data/specs/gzipfile/to_io_spec.rb +2 -0
  28. data/specs/gzipfile/wrap_spec.rb +2 -0
  29. data/specs/gzipreader/each_byte_spec.rb +2 -0
  30. data/specs/gzipreader/each_line_spec.rb +2 -0
  31. data/specs/gzipreader/each_spec.rb +2 -0
  32. data/specs/gzipreader/eof_spec.rb +23 -0
  33. data/specs/gzipreader/getc_spec.rb +2 -0
  34. data/specs/gzipreader/gets_spec.rb +2 -0
  35. data/specs/gzipreader/lineno_spec.rb +2 -0
  36. data/specs/gzipreader/new_spec.rb +2 -0
  37. data/specs/gzipreader/open_spec.rb +2 -0
  38. data/specs/gzipreader/pos_spec.rb +27 -0
  39. data/specs/gzipreader/read_spec.rb +29 -0
  40. data/specs/gzipreader/readchar_spec.rb +2 -0
  41. data/specs/gzipreader/readline_spec.rb +2 -0
  42. data/specs/gzipreader/readlines_spec.rb +2 -0
  43. data/specs/gzipreader/rewind_spec.rb +34 -0
  44. data/specs/gzipreader/tell_spec.rb +2 -0
  45. data/specs/gzipreader/ungetc_spec.rb +2 -0
  46. data/specs/gzipreader/unused_spec.rb +2 -0
  47. data/specs/gzipwriter/append_spec.rb +2 -0
  48. data/specs/gzipwriter/comment_spec.rb +2 -0
  49. data/specs/gzipwriter/flush_spec.rb +2 -0
  50. data/specs/gzipwriter/mtime_spec.rb +42 -0
  51. data/specs/gzipwriter/new_spec.rb +2 -0
  52. data/specs/gzipwriter/open_spec.rb +2 -0
  53. data/specs/gzipwriter/orig_name_spec.rb +2 -0
  54. data/specs/gzipwriter/pos_spec.rb +2 -0
  55. data/specs/gzipwriter/print_spec.rb +2 -0
  56. data/specs/gzipwriter/printf_spec.rb +2 -0
  57. data/specs/gzipwriter/putc_spec.rb +2 -0
  58. data/specs/gzipwriter/puts_spec.rb +2 -0
  59. data/specs/gzipwriter/tell_spec.rb +2 -0
  60. data/specs/gzipwriter/write_spec.rb +23 -0
  61. data/specs/inflate/append_spec.rb +12 -0
  62. data/specs/inflate/inflate_spec.rb +49 -0
  63. data/specs/inflate/new_spec.rb +2 -0
  64. data/specs/inflate/set_dictionary_spec.rb +20 -0
  65. data/specs/inflate/sync_point_spec.rb +2 -0
  66. data/specs/inflate/sync_spec.rb +2 -0
  67. data/specs/zlib_version_spec.rb +2 -0
  68. data/specs/zstream/adler_spec.rb +1 -0
  69. data/specs/zstream/avail_in_spec.rb +1 -0
  70. data/specs/zstream/avail_out_spec.rb +1 -0
  71. data/specs/zstream/close_spec.rb +2 -0
  72. data/specs/zstream/closed_spec.rb +2 -0
  73. data/specs/zstream/data_type_spec.rb +2 -0
  74. data/specs/zstream/end_spec.rb +2 -0
  75. data/specs/zstream/ended_spec.rb +2 -0
  76. data/specs/zstream/finish_spec.rb +2 -0
  77. data/specs/zstream/finished_spec.rb +2 -0
  78. data/specs/zstream/flush_next_in_spec.rb +2 -0
  79. data/specs/zstream/flush_next_out_spec.rb +16 -0
  80. data/specs/zstream/reset_spec.rb +2 -0
  81. data/specs/zstream/stream_end_spec.rb +2 -0
  82. data/specs/zstream/total_in_spec.rb +2 -0
  83. data/specs/zstream/total_out_spec.rb +2 -0
  84. metadata +137 -0
data/CHANGES ADDED
@@ -0,0 +1,5 @@
1
+ ==Version History
2
+ ===0.0.2
3
+ * Gzip decompression added (NOTE: Does not currently do CRC checking, nor multiple file gzips)
4
+ ===0.0.1
5
+ * Initial Version, only supports Zlib deflate
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2008, Michael Letterle
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ * Neither the name of Zliby nor the names of its contributors may be used
13
+ to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,33 @@
1
+ = Zliby: Pure Ruby Zlib
2
+ === Version Information
3
+ Release:: 0.0.5
4
+ Description:: A Ruby 1.8.6 Zlib compatible module.
5
+ Reference:: Zlib[http://www.zlib.net] 1.2.3
6
+
7
+ == Introduction
8
+
9
+ Zliby is an implmention of the Zlib[http://www.zlib.net] library written in
10
+ pure Ruby. It is meant to be API compatible with the existing Ruby Zlib
11
+ extension library. The purpose of this library was two-fold:
12
+
13
+ 1. To see if it could be done
14
+ 2. To provide IronRuby[http://www.ironruby.net] with a compatible Zlib
15
+ implementation
16
+
17
+ While IronRuby[http://www.ironruby.net] was the inspirition for this project,
18
+ the fact that it's written in pure Ruby means any Ruby implementation should
19
+ benefit.
20
+
21
+ === Acknowledgements
22
+
23
+ The deflate implmentation is essentially a port of puff.c from the Zlib[http://www.zlib.net]
24
+ implementation by Jean-loup Gailly and Mark Adler. All due praise should be
25
+ directed their way.
26
+
27
+ ==== Author
28
+
29
+ Author:: Michael Letterle [ theprokrammer [ a t ] prokrams.com ]
30
+ Copyright:: 2008 by Michael Letterle
31
+
32
+ == License
33
+ :include: LICENSE
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ ==Zliby[http://zliby.rubyforge.org] TODOs
2
+
3
+ * Finish implementing Ruby-core Zlib API
4
+ * Add tar support
5
+ * Add bzip2 support
6
+ * Add PKZIP support
data/bin/zliber ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ begin
3
+ require 'zliby'
4
+ rescue LoadError
5
+ require 'rubygems'
6
+ require 'zliby'
7
+ end
data/lib/zliby.rb ADDED
@@ -0,0 +1,624 @@
1
+ require 'stringio'
2
+
3
+ module Zlib
4
+ ZLIBY_VERSION = "0.0.5"
5
+ ZLIB_VERSION = "1.2.3"
6
+ VERSION = "0.6.0" #For compatibility with Ruby-core Zlib
7
+ MAXBITS = 15
8
+ MAXLCODES = 286
9
+ MAXDCODES = 30
10
+ MAXCODES = (MAXLCODES+MAXDCODES)
11
+ FIXLCODES = 288
12
+ MAX_WBITS = 15
13
+ Z_DEFLATED = 8
14
+
15
+ def self.adler32 string="", adler=1
16
+ if adler > (2**128) - 1 then raise RangeError.new end
17
+ accum1 = adler & 0xffff
18
+ accum2 = (adler >> 16) & 0xffff
19
+
20
+ len = string.length
21
+ x = -1
22
+ while len > 0
23
+ tlen = len > 5552 ? 5552 : len
24
+ len -= tlen
25
+ while tlen >0
26
+ x += 1
27
+ accum1 += string[x]
28
+ accum2 += accum1
29
+ tlen -= 1
30
+ end
31
+ accum1 %= 65521
32
+ accum2 %= 65521
33
+ end
34
+ accum2 << 16 | accum1
35
+ end
36
+
37
+ def self.crc_table
38
+ [0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117]
39
+ end
40
+
41
+ def self.crc32 string="", crc=0
42
+ if crc > 2**128 - 1 then raise RangeError.new end
43
+ crc = crc ^ 0xffffffff
44
+ string.each_byte do |byte|
45
+ index = (crc ^ byte) & 0xff
46
+ crc = (crc >> 8) ^ crc_table[index]
47
+ end
48
+ crc ^ 0xffffffff
49
+ end
50
+
51
+
52
+ class ZStream
53
+
54
+ def initialize
55
+ @input_buffer = []
56
+ @output_buffer = []
57
+ @out_pos = -1
58
+ @in_pos = -1
59
+ @bit_bucket = 0
60
+ @bit_count = 0
61
+
62
+ end
63
+ #Returns the adler-32 checksum of the input data.
64
+ def adler
65
+ end
66
+
67
+ #Returns the number of bytes read. Normally 0 since all bytes are read at once.
68
+ def avail_in
69
+ @input_buffer.length - @in_pos
70
+ end
71
+
72
+ #Returns number of free bytes in the output buffer. As the output buffer is self expanding this normally returns 0.
73
+ def avail_out
74
+ @output_buffer.length - @out_pos
75
+ end
76
+
77
+ #Allocates size bytes in output buffer. If size < avail_out it truncates the buffer.
78
+ def avail_out= size
79
+ size.times do
80
+ if size > avail_out
81
+ @output_buffer.push nil
82
+ else
83
+ @output_buffer.pop
84
+ end
85
+ end
86
+ end
87
+
88
+ #Closes stream. Further operations will raise Zlib::StreamError
89
+ def close
90
+ @closed = true
91
+ end
92
+
93
+ #True if stream closed, otherwise False.
94
+ def closed?
95
+ @closed
96
+ end
97
+
98
+ #Best guess of input data, one of Zlib::BINARY, Zlib::ASCII, or Zlib::UNKNOWN
99
+ def data_type
100
+ end
101
+
102
+ #See close
103
+ def end
104
+ close
105
+ end
106
+
107
+ #See closed?
108
+ def ended?
109
+ closed?
110
+ end
111
+
112
+ #Finishes the stream, flushes output buffer, implemented by child classes
113
+ def finish
114
+ close
115
+ end
116
+
117
+ #True if stream is finished, otherwise False
118
+ def finished?
119
+ if @finished.nil? then
120
+ false
121
+ else
122
+ @finished
123
+ end
124
+ end
125
+
126
+ #Flushes input buffer and returns the data therein.
127
+ def flush_next_in
128
+ @in_pos = @input_buffer.length
129
+ @finished = true
130
+ ret = @input_buffer.pack("c*")
131
+ @input_buffer = []
132
+ ret
133
+ end
134
+
135
+ #Flushes the output buffer and returns all the data
136
+ def flush_next_out
137
+ @out_pos = @output_buffer.length
138
+ @finished = true
139
+ ret = @output_buffer.pack("c*")
140
+ @output_buffer = []
141
+ ret
142
+ end
143
+
144
+ #Reset stream. Input and Output buffers are reset.
145
+ def reset
146
+ @out_pos = -1
147
+ @in_pos = -1
148
+ @input_buffer = []
149
+ @output_buffer = []
150
+ end
151
+
152
+ #See finished.
153
+ def stream_end?
154
+ finished?
155
+ end
156
+
157
+ #Size of input buffer.
158
+ def total_in
159
+ @input_buffer.length
160
+ end
161
+
162
+ #Size of output buffer.
163
+ def total_out
164
+ @output_buffer.length
165
+ end
166
+
167
+ private
168
+ #returns need bits from the input buffer
169
+ # == Format Notes
170
+ # bits are stored LSB to MSB
171
+ def get_bits need
172
+ val = @bit_bucket
173
+ while @bit_count < need
174
+ val |= (@input_buffer[@in_pos+=1] << @bit_count)
175
+ @bit_count += 8
176
+ end
177
+
178
+ @bit_bucket = val >> need
179
+ @bit_count -= need
180
+ val & ((1 << need) - 1)
181
+ end
182
+ public
183
+ end
184
+
185
+ #== DEFLATE Decompression
186
+ #Implements decompression of a RFC-1951[ftp://ftp.rfc-editor.org/in-notes/rfc1951.txt] compatible stream.
187
+ class Inflate < ZStream
188
+
189
+ def initialize window_bits=MAX_WBITS
190
+ @w_bits = window_bits
191
+ if @w_bits < 0 then
192
+ @rawdeflate = true
193
+ @w_bits *= -1
194
+ end
195
+ super()
196
+ @zstring = ""
197
+ end
198
+
199
+ #Appends data to the input stream
200
+ def <<(string)
201
+ @zstring << string
202
+ inflate
203
+ end
204
+
205
+ #Sets the inflate dictionary
206
+ def set_dictionary string
207
+ @dict = string
208
+ reset
209
+ end
210
+
211
+ #==Example
212
+ # f = File.open "example.z"
213
+ # i = Inflate.new
214
+ # i.inflate f.read
215
+ def inflate zstring=nil
216
+ @zstring = zstring unless zstring.nil?
217
+ #We can't use unpack, IronRuby doesn't have it yet.
218
+ @zstring.each_byte {|b| @input_buffer << b}
219
+
220
+ unless @rawdeflate then
221
+
222
+ compression_method_and_flags = @input_buffer[@in_pos+=1]
223
+ flags = @input_buffer[@in_pos+=1]
224
+
225
+ #CMF and FLG, when viewed as a 16-bit unsigned integer stored inMSB order (CMF*256 + FLG), is a multiple of 31
226
+ if ((compression_method_and_flags << 0x08) + flags) % 31 != 0 then raise Zlib::DataError.new("incorrect header check") end
227
+
228
+ #CM = 8 denotes the �deflate� compression method with a window size up to 32K. (RFC's only specify CM 8)
229
+ compression_method = compression_method_and_flags & 0x0F
230
+
231
+ if compression_method != Z_DEFLATED then raise Zlib::DataError.new("unknown compression method") end
232
+
233
+ #For CM = 8, CINFO is the base-2 logarithm of the LZ77 window size,minus eight (CINFO=7 indicates a 32K window size)
234
+ compression_info = compression_method_and_flags >> 0x04
235
+
236
+ if (compression_info + 8) > @w_bits then raise Zlib::DataError.new("invalid window size") end
237
+
238
+ preset_dictionary_flag = ((flags & 0x20) >> 0x05) == 1
239
+ compression_level = (flags & 0xC0) >> 0x06
240
+
241
+ if preset_dictionary_flag and @dict.nil? then raise Zlib::NeedDict.new "Preset dictionary needed!" end
242
+
243
+ #TODO: Add Preset dictionary support
244
+ if preset_dictionary_flag then
245
+ @dict_crc = @input_buffer[@in_pos+=1] << 24 | @input_buffer[@in_pos+=1] << 16 | @input_buffer[@in_pos+=1] << 8 | @input_buffer[@in_pos+=1]
246
+ end
247
+
248
+ end
249
+ last_block = false
250
+ #Begin processing DEFLATE stream
251
+ until last_block
252
+ last_block = (get_bits(1) == 1)
253
+ block_type = get_bits(2)
254
+ case block_type
255
+ when 0 then no_compression
256
+ when 1 then fixed_codes
257
+ when 2 then dynamic_codes
258
+ when 3 then raise Zlib::DataError.new("invalid block type")
259
+ end
260
+ end
261
+ finish
262
+ end
263
+
264
+ #Finishes inflating and flushes the buffer
265
+ def finish
266
+ output = ""
267
+ inflate unless @output_buffer.length > 0
268
+ @output_buffer.each {|c| output << c }
269
+ super
270
+ output
271
+ end
272
+
273
+ private
274
+
275
+ def no_compression
276
+ @bit_bucket = 0
277
+ @bit_count = 0
278
+ if @in_pos + 4 > @input_buffer.length then raise Zlib::DataError.new("not enough input to read length code") end
279
+ length = @input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8)
280
+
281
+ if (~length & 0xff != @input_buffer[@in_pos+=1]) || (((~length >> 8) & 0xff) != @input_buffer[@in_pos+=1]) then raise Zlib::DataError.new("invalid stored block lengths") end
282
+
283
+ if @in_pos + length > @input_buffer.length then raise Zlib::DataError.new("ran out of input") end
284
+
285
+
286
+ length.times do
287
+ @output_buffer[@out_pos += 1] = @input_buffer[@in_pos += 1]
288
+ end
289
+
290
+
291
+ end
292
+
293
+ def fixed_codes
294
+ if @fixed_length_codes.nil? && @fixed_distance_codes.nil? then generate_huffmans end
295
+ codes @fixed_length_codes, @fixed_distance_codes
296
+ end
297
+
298
+ def dynamic_codes
299
+
300
+ order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
301
+ nlen = get_bits(5) + 257
302
+ ndist = get_bits(5) + 1
303
+ ncode = get_bits(4) + 4
304
+
305
+
306
+ lengths=[]
307
+ dynamic_length_codes = Zlib::Inflate::HuffmanTree.new
308
+ dynamic_distance_codes = Zlib::Inflate::HuffmanTree.new
309
+
310
+ if (nlen > MAXLCODES || ndist > MAXDCODES) then raise Zlib::DataError.new("too many length or distance codes") end
311
+ idx = 0
312
+
313
+ while idx < ncode
314
+ lengths[order[idx]] = get_bits(3)
315
+ idx += 1
316
+ end
317
+ while idx < 19
318
+ lengths[order[idx]] = 0
319
+ idx += 1
320
+ end
321
+ err = construct_tree dynamic_length_codes, lengths, 18
322
+ if err != 0 then raise Zlib::DataError.new("code lengths codes incomplete") end
323
+
324
+ idx = 0
325
+ while idx < (nlen + ndist)
326
+ symbol = decode(dynamic_length_codes)
327
+ if symbol < 16 then
328
+ lengths[idx] = symbol
329
+ idx += 1;
330
+ else
331
+ len = 0
332
+ if symbol == 16 then
333
+ if idx == 0 then raise Zlib::DataError.new("repeat lengths with no first length") end
334
+ len = lengths[idx - 1]
335
+ symbol = 3 + get_bits(2)
336
+ elsif symbol == 17 then
337
+ symbol = 3 + get_bits(3)
338
+ elsif symbol == 18 then
339
+ symbol = 11 + get_bits(7)
340
+ else
341
+ raise Zlib::DataError.new("invalid repeat length code")
342
+ end
343
+ if (idx + symbol) > (nlen + ndist) then raise Zlib::DataError.new("repeat more than specified lengths") end
344
+ until symbol == 0
345
+ lengths[idx] = len
346
+ idx+=1
347
+ symbol -= 1
348
+ end
349
+ end
350
+ end
351
+
352
+ err = construct_tree dynamic_length_codes, lengths, nlen-1
353
+
354
+ if err < 0 || (err > 0 && (nlen - dynamic_length_codes.count[0] != 1)) then raise Zlib::DataError.new("invalid literal/length code lengths") end
355
+
356
+ nlen.times { lengths.delete_at 0 } #We do this since we don't have pointer arithmetic in ruby
357
+
358
+ err = construct_tree dynamic_distance_codes, lengths, ndist-1
359
+ if err < 0 || (err > 0 && (ndist - dynamic_distance_codes.count[0] != 1)) then raise Zlib::DataError.new("invalid distance code lengths") end
360
+
361
+ codes dynamic_length_codes, dynamic_distance_codes
362
+ end
363
+
364
+ def generate_huffmans
365
+
366
+ lengths = []
367
+
368
+ #literal/length table
369
+ for idx in (000..143)
370
+ lengths[idx] = 8
371
+ end
372
+ for idx in (144..255)
373
+ lengths[idx] = 9
374
+ end
375
+ for idx in (256..279)
376
+ lengths[idx] = 7
377
+ end
378
+ for idx in (280..287)
379
+ lengths[idx] = 8
380
+ end
381
+ @fixed_length_codes = Zlib::Inflate::HuffmanTree.new
382
+ construct_tree @fixed_length_codes, lengths, 287
383
+
384
+ for idx in (00..29)
385
+ lengths[idx] = 5
386
+ end
387
+ @fixed_distance_codes = Zlib::Inflate::HuffmanTree.new
388
+ construct_tree @fixed_distance_codes, lengths, 29
389
+
390
+ end
391
+
392
+ def codes length_codes, distance_codes
393
+ lens = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258]
394
+ lext = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]
395
+ dists = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577]
396
+ dext = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]
397
+
398
+ symbol = 0
399
+
400
+ until symbol == 256
401
+ symbol = decode(length_codes)
402
+ if symbol < 0 then return symbol end
403
+ if symbol < 256 then @output_buffer[@out_pos+=1] = symbol end
404
+ if symbol > 256 then
405
+ symbol -= 257
406
+ if symbol >= 29 then raise Zlib::DataError.new("invalid literal/length or distance code in fixed or dynamic block") end
407
+ len = lens[symbol] + get_bits(lext[symbol])
408
+ symbol = decode(distance_codes)
409
+ if symbol < 0 then return symbol end
410
+ dist = dists[symbol] + get_bits(dext[symbol])
411
+ if dist > @output_buffer.length then raise Zlib::DataError.new("distance is too far back in fixed or dynamic block") end
412
+ while len > 0
413
+ @output_buffer[@out_pos+=1] = @output_buffer[@out_pos - dist]
414
+ len -= 1
415
+ end
416
+ end
417
+ end
418
+ return 0
419
+ end
420
+
421
+ def decode huffman_tree
422
+ code = 0
423
+ first = 0
424
+ index = 0
425
+ for len in (1..15)
426
+ code |= get_bits(1)
427
+ count = huffman_tree.count[len]
428
+ if code < (first + count) then return huffman_tree.symbol[index + (code - first)] end
429
+ index += count
430
+ first += count
431
+ first <<= 1
432
+ code <<= 1
433
+ end
434
+ -9
435
+ end
436
+
437
+ def construct_tree huffman_tree, lengths, n_symbols
438
+ offs = []
439
+
440
+ for len in (000..MAXBITS)
441
+ huffman_tree.count[len] = 0
442
+ end
443
+
444
+ for symbol in (000..n_symbols)
445
+ huffman_tree.count[lengths[symbol]] += 1
446
+ end
447
+
448
+ if huffman_tree.count[0] == n_symbols then return 0 end
449
+
450
+ left = 1
451
+ for len in (1..MAXBITS)
452
+ left <<= 1
453
+ left -= huffman_tree.count[len];
454
+ if left < 0 then return left end
455
+ end
456
+
457
+ offs[1] = 0
458
+
459
+ for len in (1..(MAXBITS-1))
460
+ offs[len+1] = offs[len] + huffman_tree.count[len]
461
+ end
462
+
463
+ for symbol in (0..n_symbols)
464
+ if lengths[symbol] != 0 then
465
+ huffman_tree.symbol[offs[lengths[symbol]]] = symbol
466
+ offs[lengths[symbol]] += 1
467
+ end
468
+
469
+ end
470
+ left
471
+ end
472
+
473
+ class HuffmanTree
474
+ attr_accessor :count, :symbol
475
+ def initialize
476
+ @count = []
477
+ @symbol = []
478
+ end
479
+ end
480
+
481
+ class << self
482
+ def inflate zstring
483
+ d = self.new
484
+ d.inflate zstring
485
+ end
486
+ end
487
+
488
+ end
489
+
490
+
491
+ class GzipFile
492
+
493
+ def initialize
494
+ @input_buffer = []
495
+ @output_buffer = []
496
+ @out_pos = -1
497
+ @in_pos = -1
498
+ end
499
+
500
+ def close
501
+ end
502
+
503
+ class Error < Exception
504
+ end
505
+
506
+ end
507
+
508
+ class GzipReader < GzipFile
509
+ OSES = ['FAT filesystem',
510
+ 'Amiga',
511
+ 'VMS (or OpenVMS)',
512
+ 'Unix',
513
+ 'VM/CMS',
514
+ 'Atari TOS',
515
+ 'HPFS fileystem (OS/2, NT)',
516
+ 'Macintosh',
517
+ 'Z-System',
518
+ 'CP/M',
519
+ 'TOPS-20',
520
+ 'NTFS filesystem (NT)',
521
+ 'QDOS',
522
+ 'Acorn RISCOS',
523
+ 'unknown']
524
+
525
+ def initialize io
526
+
527
+ #Add a helper method to check bits
528
+ ::Fixnum.module_eval do
529
+ def isbitset? bit_to_check
530
+ if self & (2 ** bit_to_check) == (2 ** bit_to_check) then true else false end
531
+ end
532
+ end
533
+
534
+ super()
535
+ @io = io
536
+ io.read.each_byte {|b| @input_buffer << b}
537
+ if @input_buffer[@in_pos+=1] != 0x1f || @input_buffer[@in_pos+=1] != 0x8b then raise Zlib::GzipFile::Error.new("not in gzip format") end
538
+ if @input_buffer[@in_pos+=1] != 0x08 then raise Zlib::GzipFile::Error.new("unknown compression method") end
539
+ flg = @input_buffer[@in_pos+=1]
540
+ @ftext = flg.isbitset? 0
541
+ @fhcrc = flg.isbitset? 1
542
+ @fextra = flg.isbitset? 2
543
+ @fname = flg.isbitset? 3
544
+ @fcomment = flg.isbitset? 4
545
+ @mtime = Time.at(@input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8) | (@input_buffer[@in_pos+=1] << 16) | (@input_buffer[@in_pos+=1] << 24))
546
+ @xfl = @input_buffer[@in_pos+=1]
547
+ @os = OSES[@input_buffer[@in_pos+=1]]
548
+ if @fextra then
549
+ @xlen = (@input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8))
550
+ @xtra_field = []
551
+ @xlen.times {@xtra_field << @input_buffer[@in_pos+=1]}
552
+ end
553
+ if @fname then
554
+ @original_name = ""
555
+ until @original_name["\0"].nil? == false
556
+ @original_name.concat(@input_buffer[@in_pos+=1])
557
+ end
558
+ @original_name.chop!
559
+ end
560
+ if @fcomment then
561
+ @comment = ""
562
+ until @comment["\0"].nil? == false
563
+ @comment.concat(@input_buffer[@in_pos+=1])
564
+ end
565
+ @comment.chop!
566
+ end
567
+ if @fhcrc then
568
+ @header_crc = @input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8)
569
+ end
570
+ @contents = ""
571
+ until @in_pos == @input_buffer.length-1
572
+ @contents.concat(@input_buffer[@in_pos+=1])
573
+ end
574
+
575
+ #we do raw deflate, no headers
576
+ @zstream = Zlib::Inflate.new -MAX_WBITS
577
+ @inflated = StringIO.new(@zstream.inflate @contents)
578
+
579
+ end
580
+
581
+ def read length=nil
582
+ @inflated.read length
583
+ end
584
+
585
+ def eof?
586
+ @inflated.eof?
587
+ end
588
+
589
+ def pos
590
+ @inflated.pos
591
+ end
592
+
593
+ def rewind
594
+ @inflated.rewind
595
+ @io.seek 0, IO::SEEK_SET
596
+ end
597
+
598
+ class << self
599
+
600
+ def open filename
601
+ io = File.open filename
602
+ gz = self.new io
603
+ if block_given? then yield gz else gz end
604
+ end
605
+
606
+ end
607
+ end
608
+
609
+
610
+ #Generic Error
611
+ class Error < Exception
612
+ end
613
+
614
+ #Dictionary Needed
615
+ class NeedDict < Error
616
+ end
617
+
618
+ #Invalid Data
619
+ class DataError < Error
620
+ end
621
+
622
+ end
623
+
624
+