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.
- 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
|
+
|