class PoiseArchive::Bzip2::Decompressor
This code is free software; you can redistribute it and/or modify it under the terms of the new BSD License.
Copyright © 2011-2013, Sebastian Staudt
Public Class Methods
new(io)
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 11 def initialize(io) @buff = 0 @bytes_read = 0 @computed_combined_crc = 0 @crc = PoiseArchive::Bzip2::CRC.new @current_char = -1 @io = io @live = 0 @stored_combined_crc = 0 @su_t_pos = 0 init end
Public Instance Methods
bit()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 190 def bit r(1) != 0 end
check_magic()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 113 def check_magic raise 'Magic number does not match "BZh".' unless @io.read(3) == 'BZh' end
close()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 161 def close if @io != $stdin @io = nil @data = nil end end
complete()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 153 def complete @stored_combined_crc = int @current_state = EOF @data = nil raise 'BZip2 CRC error' if @stored_combined_crc != @computed_combined_crc end
count(read)
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 24 def count(read) @bytes_read += read if read != -1 end
create_decode_tables(limit, base, perm, length, min_len, max_len, alpha_size)
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 202 def create_decode_tables(limit, base, perm, length, min_len, max_len, alpha_size) pp = 0 (min_len..max_len).each do |i| alpha_size.times do |j| if length[j] == i perm[pp] = j pp += 1 end end end MAX_CODE_LEN.downto 1 do |i| base[i] = 0 limit[i] = 0 end alpha_size.times do |i| base[length[i] + 1] += 1 end b = 0 1.upto(MAX_CODE_LEN - 1) do |i| b += base[i] base[i] = b end vec = 0 min_len.upto(max_len) do |i| b = base[i] nb = base[i + 1] vec += nb - b b = nb limit[i] = vec - 1 vec = vec << 1 end (min_len + 1).upto(max_len) do |i| base[i] = ((limit[i - 1] + 1) << 1) - base[i] end end
create_huffman_decoding_tables(alpha_size, groups)
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 315 def create_huffman_decoding_tables(alpha_size, groups) len = @data.temp_char_array_2d min_lens = @data.min_lens limit = @data.limit base = @data.base perm = @data.perm groups.times do |t| min_len = 32 max_len = 0 len_t = len[t] (alpha_size - 1).downto 0 do |i| lent = len_t[i] max_len = lent if lent > max_len min_len = lent if lent < min_len end create_decode_tables limit[t], base[t], perm[t], len[t], min_len, max_len, alpha_size min_lens[t] = min_len end end
end_block()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 139 def end_block @computed_block_crc = @crc.final_crc if @stored_block_crc != @computed_block_crc @computed_combined_crc = (@stored_combined_crc << 1) | (@stored_combined_crc >> 31) @computed_combined_crc ^= @stored_block_crc raise 'BZip2 CRC error' end @computed_combined_crc = (@computed_combined_crc << 1) | (@computed_combined_crc >> 31) @computed_combined_crc ^= @computed_block_crc end
eof?()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 33 def eof? @current_state == EOF end
get_and_move_to_front_decode()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 338 def get_and_move_to_front_decode @orig_ptr = r 24 receive_decoding_tables ll8 = @data.ll8 unzftab = @data.unzftab selector = @data.selector seq_to_unseq = @data.seq_to_unseq yy = @data.get_and_move_to_front_decode_yy min_lens = @data.min_lens limit = @data.limit base = @data.base perm = @data.perm limit_last = @block_size * BASEBLOCKSIZE 256.downto(0) do |i| yy[i] = i unzftab[i] = 0 end group_no = 0 group_pos = G_SIZE - 1 eob = @n_in_use + 1 next_sym = get_and_move_to_front_decode0 0 buff_shadow = @buff live_shadow = @live last_shadow = -1 zt = selector[group_no] & 0xff base_zt = base[zt] limit_zt = limit[zt] perm_zt = perm[zt] min_lens_zt = min_lens[zt] while next_sym != eob if (next_sym == RUNA) || (next_sym == RUNB) s = -1 n = 1 while true do if next_sym == RUNA s += n elsif next_sym == RUNB s += n << 1 else break end if group_pos == 0 group_pos = G_SIZE - 1 group_no += 1 zt = selector[group_no] & 0xff base_zt = base[zt] limit_zt = limit[zt] perm_zt = perm[zt] min_lens_zt = min_lens[zt] else group_pos -= 1 end zn = min_lens_zt while live_shadow < zn thech = @io.readbyte raise 'unexpected end of stream' if thech < 0 buff_shadow = ((buff_shadow << 8) & 0xffffffff) | thech live_shadow += 8 end zvec = ((buff_shadow >> (live_shadow - zn)) & 0xffffffff) & ((1 << zn) - 1) live_shadow -= zn while zvec > limit_zt[zn] zn += 1 while live_shadow < 1 thech = @io.readbyte raise 'unexpected end of stream' if thech < 0 buff_shadow = ((buff_shadow << 8) & 0xffffffff) | thech live_shadow += 8 end live_shadow -= 1 zvec = (zvec << 1) | ((buff_shadow >> live_shadow) & 1) end next_sym = perm_zt[zvec - base_zt[zn]] n = n << 1 end ch = seq_to_unseq[yy[0]] unzftab[ch & 0xff] += s + 1 while s >= 0 last_shadow += 1 ll8[last_shadow] = ch s -= 1 end raise 'block overrun' if last_shadow >= limit_last else last_shadow += 1 raise 'block overrun' if last_shadow >= limit_last tmp = yy[next_sym - 1] unzftab[seq_to_unseq[tmp] & 0xff] += 1 ll8[last_shadow] = seq_to_unseq[tmp] yy[1, next_sym - 1] = yy[0, next_sym - 1] yy[0] = tmp if group_pos == 0 group_pos = G_SIZE - 1 group_no += 1 zt = selector[group_no] & 0xff base_zt = base[zt] limit_zt = limit[zt] perm_zt = perm[zt] min_lens_zt = min_lens[zt] else group_pos -= 1 end zn = min_lens_zt while live_shadow < zn thech = @io.readbyte raise 'unexpected end of stream' if thech < 0 buff_shadow = ((buff_shadow << 8) & 0xffffffff) | thech live_shadow += 8 end zvec = (buff_shadow >> (live_shadow - zn)) & ((1 << zn) - 1) live_shadow -= zn while zvec > limit_zt[zn] zn += 1 while live_shadow < 1 thech = @io.readbyte raise 'unexpected end of stream' if thech < 0 buff_shadow = ((buff_shadow << 8) & 0xffffffff) | thech live_shadow += 8 end live_shadow -= 1 zvec = (zvec << 1) | ((buff_shadow >> live_shadow) & 1) end next_sym = perm_zt[zvec - base_zt[zn]] end end @last = last_shadow @live = live_shadow @buff = buff_shadow end
get_and_move_to_front_decode0(group_no)
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 501 def get_and_move_to_front_decode0(group_no) zt = @data.selector[group_no] & 0xff limit_zt = @data.limit[zt] zn = @data.min_lens[zt] zvec = r zn live_shadow = @live buff_shadow = @buff while zvec > limit_zt[zn] zn += 1 while live_shadow < 1 thech = @io.readbyte raise 'unexpected end of stream' if thech < 0 buff_shadow = ((buff_shadow << 8) & 0xffffffff) | thech live_shadow += 8 end live_shadow -=1 zvec = (zvec << 1) | ((buff_shadow >> live_shadow) & 1) end @live = live_shadow @buff = buff_shadow @data.perm[zt][zvec - @data.base[zt][zn]] end
init()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 102 def init check_magic block_size = @io.read(1).to_i raise 'Illegal block size.' if block_size < 1 || block_size > 9 @block_size = block_size init_block setup_block end
init_block()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 117 def init_block magic = [ubyte, ubyte, ubyte, ubyte, ubyte, ubyte] if magic == [0x17, 0x72, 0x45, 0x38, 0x50, 0x90] complete elsif magic != [0x31, 0x41, 0x59, 0x26, 0x53, 0x59] @current_state = EOF raise 'Bad block header.' else @stored_block_crc = int @block_randomised = bit @data = PoiseArchive::Bzip2::InputData.new @block_size if @data.nil? get_and_move_to_front_decode @crc.initialize_crc @current_state = START_BLOCK_STATE end end
inspect()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 700 def inspect "#<#{self.class}: @io=#{@io.inspect} size=#{size} uncompressed=#{uncompressed}>" end
int()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 198 def int (((((r(8) << 8) | r(8)) << 8) | r(8)) << 8) | r(8) end
make_maps()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 86 def make_maps in_use = @data.in_use seq_to_unseq = @data.seq_to_unseq n_in_use_shadow = 0 256.times do |i| if in_use[i] seq_to_unseq[n_in_use_shadow] = i n_in_use_shadow += 1 end end @n_in_use = n_in_use_shadow end
pos()
click to toggle source
ADDED METHODS
# File lib/poise_archive/bzip2/decompressor.rb, line 29 def pos @bytes_read end
r(n)
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 168 def r(n) live_shadow = @live buff_shadow = @buff if live_shadow < n begin thech = @io.readbyte raise 'unexpected end of stream' if thech < 0 buff_shadow = (buff_shadow << 8) | thech live_shadow += 8 end while live_shadow < n @buff = buff_shadow end @live = live_shadow - n (buff_shadow >> (live_shadow - n)) & ((1 << n) - 1) end
read(length = nil)
click to toggle source
/ADDED METHODS
# File lib/poise_archive/bzip2/decompressor.rb, line 38 def read(length = nil) raise 'stream closed' if @io.nil? if length == 1 r = read0 count (r < 0 ? -1 : 1) r else r = '' if length == nil while true do b = read0 break if b < 0 r << b.chr end count r.size # ADDED LINE elsif length > 0 length.times do b = read0 break if b < 0 r << b.chr end count r.size end r end end
read0()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 66 def read0 ret_char = @current_char if @current_state == RAND_PART_B_STATE setup_rand_part_b elsif @current_state == NO_RAND_PART_B_STATE setup_no_rand_part_b elsif @current_state == RAND_PART_C_STATE setup_rand_part_c elsif @current_state == NO_RAND_PART_C_STATE setup_no_rand_part_c elsif @current_state == EOF return -1 else raise 'illegal state' end ret_char end
receive_decoding_tables()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 243 def receive_decoding_tables in_use = @data.in_use pos = @data.receive_decoding_tables_pos selector = @data.selector selector_mtf = @data.selector_mtf in_use16 = 0 16.times do |i| in_use16 |= 1 << i if bit end 255.downto(0) do |i| in_use[i] = false end 16.times do |i| if (in_use16 & (1 << i)) != 0 i16 = i << 4 16.times do |j| in_use[i16 + j] = true if bit end end end make_maps alpha_size = @n_in_use + 2 groups = r 3 selectors = r 15 selectors.times do |i| j = 0 while bit j += 1 end selector_mtf[i] = j end groups.downto(0) do |v| pos[v] = v end selectors.times do |i| v = selector_mtf[i] & 0xff tmp = pos[v] while v > 0 do pos[v] = pos[v -= 1] end pos[0] = tmp selector[i] = tmp end len = @data.temp_char_array_2d groups.times do |t| curr = r 5 len_t = len[t] alpha_size.times do |i| while bit curr += bit ? -1 : 1 end len_t[i] = curr end @data.temp_char_array_2d[t] = len_t end create_huffman_decoding_tables alpha_size, groups end
setup_block()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 531 def setup_block return if @data.nil? cftab = @data.cftab tt = @data.init_tt @last + 1 ll8 = @data.ll8 cftab[0] = 0 cftab[1, 256] = @data.unzftab[0, 256] c = cftab[0] 1.upto(256) do |i| c += cftab[i] cftab[i] = c end last_shadow = @last (last_shadow + 1).times do |i| cftab_i = ll8[i] & 0xff tt[cftab[cftab_i]] = i cftab[cftab_i] += 1 end raise 'stream corrupted' if @orig_ptr < 0 || @orig_ptr >= tt.size @su_t_pos = tt[@orig_ptr] @su_count = 0 @su_i2 = 0 @su_ch2 = 256 if @block_randomised @su_r_n_to_go = 0 @su_r_t_pos = 0 setup_rand_part_a else setup_no_rand_part_a end end
setup_no_rand_part_a()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 596 def setup_no_rand_part_a if @su_i2 <= @last @su_ch_prev = @su_ch2 su_ch2_shadow = @data.ll8[@su_t_pos] & 0xff @su_ch2 = su_ch2_shadow @su_t_pos = @data.tt[@su_t_pos] @su_i2 += 1 @current_char = su_ch2_shadow @current_state = NO_RAND_PART_B_STATE @crc.update_crc su_ch2_shadow else @current_state = NO_RAND_PART_A_STATE end_block init_block setup_block end end
setup_no_rand_part_b()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 657 def setup_no_rand_part_b if @su_ch2 != @su_ch_prev @su_count = 1 setup_no_rand_part_a else @su_count += 1 if @su_count >= 4 @su_z = @data.ll8[@su_t_pos] & 0xff @su_t_pos = @data.tt[@su_t_pos] @su_j2 = 0 setup_no_rand_part_c else setup_no_rand_part_a end end end
setup_no_rand_part_c()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 674 def setup_no_rand_part_c if @su_j2 < @su_z su_ch2_shadow = @su_ch2 @current_char = su_ch2_shadow @crc.update_crc su_ch2_shadow @su_j2 += 1 @current_state = NO_RAND_PART_C_STATE else @su_i2 += 1 @su_count = 0 setup_no_rand_part_a end end
setup_rand_part_a()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 570 def setup_rand_part_a if @su_i2 <= @last @su_ch_prev = @su_ch2 su_ch2_shadow = @data.ll8[@su_t_pos] & 0xff @su_t_pos = @data.tt[@su_t_pos] if @su_r_n_to_go == 0 @su_r_n_to_go = RNUMS[@su_r_t_pos] - 1 @su_r_t_pos += 1 @su_r_t_pos = 0 if @su_r_t_pos == 512 else @su_r_n_to_go -= 1 end @su_ch2 = su_ch2_shadow ^= (@su_r_n_to_go == 1) ? 1 : 0 @su_i2 += 1 @current_char = su_ch2_shadow @current_state = RAND_PART_B_STATE @crc.update_crc su_ch2_shadow else end_block init_block setup_block end end
setup_rand_part_b()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 614 def setup_rand_part_b if @su_ch2 != @su_ch_prev @current_state = RAND_PART_A_STATE @su_count = 1 setup_rand_part_a else @su_count += 1 if @su_count >= 4 @su_z = @data.ll8[@su_t_pos] & 0xff @su_t_pos = @data.tt[@su_t_pos] if @su_r_n_to_go == 0 @su_r_n_to_go = RNUMS[@su_r_t_pos] - 1 @su_r_t_pos += 1 @su_r_t_pos = 0 if @su_r_t_pos == 512 else @su_r_n_to_go -= 1 end @su_j2 = 0 @current_state = RAND_PART_C_STATE @su_z ^= 1 if @su_r_n_to_go == 1 setup_rand_part_c else @current_state = RAND_PART_A_STATE setup_rand_part_a end end end
setup_rand_part_c()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 644 def setup_rand_part_c if @su_j2 < @su_z @current_char = @su_ch2 @crc.update_crc @su_ch2 @su_j2 += 1 else @current_state = RAND_PART_A_STATE @su_i2 += 1 @su_count = 0 setup_rand_part_a end end
size()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 688 def size if @io.is_a? StringIO @io.size elsif @io.is_a? File @io.stat.size end end
ubyte()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 194 def ubyte r 8 end
uncompressed()
click to toggle source
# File lib/poise_archive/bzip2/decompressor.rb, line 696 def uncompressed @last + 1 end