zliby 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +5 -0
- data/LICENSE +26 -0
- data/README +33 -0
- data/TODO +6 -0
- data/bin/zliber +7 -0
- data/lib/zliby.rb +624 -0
- data/specs/adler32_spec.rb +46 -0
- data/specs/crc32_spec.rb +52 -0
- data/specs/crc_table_spec.rb +11 -0
- data/specs/deflate/append_spec.rb +2 -0
- data/specs/deflate/deflate_spec.rb +49 -0
- data/specs/deflate/flush_spec.rb +2 -0
- data/specs/deflate/initialize_copy_spec.rb +2 -0
- data/specs/deflate/new_spec.rb +2 -0
- data/specs/deflate/params_spec.rb +21 -0
- data/specs/deflate/set_dictionary_spec.rb +14 -0
- data/specs/gzipfile/close_spec.rb +23 -0
- data/specs/gzipfile/closed_spec.rb +18 -0
- data/specs/gzipfile/comment_spec.rb +28 -0
- data/specs/gzipfile/crc_spec.rb +2 -0
- data/specs/gzipfile/finish_spec.rb +2 -0
- data/specs/gzipfile/level_spec.rb +2 -0
- data/specs/gzipfile/mtime_spec.rb +2 -0
- data/specs/gzipfile/orig_name_spec.rb +28 -0
- data/specs/gzipfile/os_code_spec.rb +2 -0
- data/specs/gzipfile/sync_spec.rb +2 -0
- data/specs/gzipfile/to_io_spec.rb +2 -0
- data/specs/gzipfile/wrap_spec.rb +2 -0
- data/specs/gzipreader/each_byte_spec.rb +2 -0
- data/specs/gzipreader/each_line_spec.rb +2 -0
- data/specs/gzipreader/each_spec.rb +2 -0
- data/specs/gzipreader/eof_spec.rb +23 -0
- data/specs/gzipreader/getc_spec.rb +2 -0
- data/specs/gzipreader/gets_spec.rb +2 -0
- data/specs/gzipreader/lineno_spec.rb +2 -0
- data/specs/gzipreader/new_spec.rb +2 -0
- data/specs/gzipreader/open_spec.rb +2 -0
- data/specs/gzipreader/pos_spec.rb +27 -0
- data/specs/gzipreader/read_spec.rb +29 -0
- data/specs/gzipreader/readchar_spec.rb +2 -0
- data/specs/gzipreader/readline_spec.rb +2 -0
- data/specs/gzipreader/readlines_spec.rb +2 -0
- data/specs/gzipreader/rewind_spec.rb +34 -0
- data/specs/gzipreader/tell_spec.rb +2 -0
- data/specs/gzipreader/ungetc_spec.rb +2 -0
- data/specs/gzipreader/unused_spec.rb +2 -0
- data/specs/gzipwriter/append_spec.rb +2 -0
- data/specs/gzipwriter/comment_spec.rb +2 -0
- data/specs/gzipwriter/flush_spec.rb +2 -0
- data/specs/gzipwriter/mtime_spec.rb +42 -0
- data/specs/gzipwriter/new_spec.rb +2 -0
- data/specs/gzipwriter/open_spec.rb +2 -0
- data/specs/gzipwriter/orig_name_spec.rb +2 -0
- data/specs/gzipwriter/pos_spec.rb +2 -0
- data/specs/gzipwriter/print_spec.rb +2 -0
- data/specs/gzipwriter/printf_spec.rb +2 -0
- data/specs/gzipwriter/putc_spec.rb +2 -0
- data/specs/gzipwriter/puts_spec.rb +2 -0
- data/specs/gzipwriter/tell_spec.rb +2 -0
- data/specs/gzipwriter/write_spec.rb +23 -0
- data/specs/inflate/append_spec.rb +12 -0
- data/specs/inflate/inflate_spec.rb +49 -0
- data/specs/inflate/new_spec.rb +2 -0
- data/specs/inflate/set_dictionary_spec.rb +20 -0
- data/specs/inflate/sync_point_spec.rb +2 -0
- data/specs/inflate/sync_spec.rb +2 -0
- data/specs/zlib_version_spec.rb +2 -0
- data/specs/zstream/adler_spec.rb +1 -0
- data/specs/zstream/avail_in_spec.rb +1 -0
- data/specs/zstream/avail_out_spec.rb +1 -0
- data/specs/zstream/close_spec.rb +2 -0
- data/specs/zstream/closed_spec.rb +2 -0
- data/specs/zstream/data_type_spec.rb +2 -0
- data/specs/zstream/end_spec.rb +2 -0
- data/specs/zstream/ended_spec.rb +2 -0
- data/specs/zstream/finish_spec.rb +2 -0
- data/specs/zstream/finished_spec.rb +2 -0
- data/specs/zstream/flush_next_in_spec.rb +2 -0
- data/specs/zstream/flush_next_out_spec.rb +16 -0
- data/specs/zstream/reset_spec.rb +2 -0
- data/specs/zstream/stream_end_spec.rb +2 -0
- data/specs/zstream/total_in_spec.rb +2 -0
- data/specs/zstream/total_out_spec.rb +2 -0
- metadata +137 -0
data/CHANGES
ADDED
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
data/bin/zliber
ADDED
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
|
+
|