| // Copyright 2023 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| // |
| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| // -------- |
| |
| // The AlgOveNN line numbers refer to the ./README.md file. |
| // |
| // Most LZMA C/C++ implementations use macros for the "decodeTheNextBym()" code |
| // fragment in that "Algorithm Overview" section, repeated multiple times in |
| // the decoding algorithm. Wuffs does not have macros (or inline functions), so |
| // its LZMA implementation looks relatively verbose and repetitive (even though |
| // it's equivalent to the C/C++ code, at the machine code level). |
| |
| pri func decoder.decode_bitstream_slow?(dst: base.io_writer, src: base.io_reader, workbuf: roslice base.u8) { |
| var c8 : base.u8 |
| |
| var bits : base.u32 |
| var range : base.u32 |
| |
| var state : base.u32[..= 11] |
| |
| // repN is what the "Algorithm Overview" calls (mrud[N] - 1). The minimum |
| // distance is 1. |
| var rep0 : base.u32[..= 0xFFFF_FFFE] |
| var rep1 : base.u32[..= 0xFFFF_FFFE] |
| var rep2 : base.u32[..= 0xFFFF_FFFE] |
| var rep3 : base.u32[..= 0xFFFF_FFFE] |
| var reptmp : base.u32[..= 0xFFFF_FFFE] |
| var rep : base.u32 |
| |
| var pos : base.u64 |
| var pos_end : base.u64 |
| |
| var lc : base.u32[..= 8] |
| var lp_mask : base.u64[..= 15] |
| var pb_mask : base.u64[..= 15] |
| |
| var prob : base.u32 |
| var threshold : base.u32 |
| var tree_node : base.u32[..= 0x1FF] |
| var prev_byte : base.u8 |
| var match_byte : base.u8 |
| var match_cusp : base.u32[..= 0xFFFF] |
| var match_bit : base.u32[..= 1] |
| var len_state : base.u32[..= 3] // Equals min(len-2, 3) when in a MATCH. |
| var slot : base.u32[..= 0x7F] |
| var len : base.u32[..= 273] |
| |
| var num_extra_bits : base.u32[..= 30] |
| var dist_extra_bits : base.u32 |
| var high_bit_was_on : base.u32 |
| var i : base.u32 |
| |
| var index_ao00 : base.u32[..= (12 << 4) - 1] |
| var index_ao41 : base.u32[..= (12 << 4) - 1] |
| var index_lit : base.u32[..= (1 << 4) - 1] |
| var index_len : base.u32[..= (1 << 4) - 1] |
| |
| var index_small_dist_base : base.u32 |
| var index_small_dist_extra : base.u32 |
| var index_small_dist : base.u32[..= 127] |
| |
| var index_large_dist : base.u32[..= 15] |
| |
| // dist is part of the Lempel-Ziv (length, distance) pair. When dist is at |
| // or below the args.dst history length then the LZ copy can be resolved |
| // just from args.dst (and adj_dist and wb_index are unused). Otherwise, if |
| // e.g. dist was 100 and args.dst.history_length() was 40 then adj_dist |
| // would be 60: the LZ copy starts 60 bytes before the end of the |
| // args.workbuf ringbuffer. wb_index is that start index, equal to |
| // ((this.dict_workbuf_index ~mod- adj_dist) modulo this.dict_size). |
| var dist : base.u32 |
| var adj_dist : base.u32 |
| var wb_index : base.u64 |
| |
| prev_byte = this.stashed_bytes[0] |
| match_byte = this.stashed_bytes[1] |
| bits = this.stashed_bits |
| range = this.stashed_range |
| state = this.stashed_state |
| rep0 = this.stashed_rep0 |
| rep1 = this.stashed_rep1 |
| rep2 = this.stashed_rep2 |
| rep3 = this.stashed_rep3 |
| pos = this.stashed_pos |
| |
| lc = this.lc |
| lp_mask = ((1 as base.u64) << this.lp) - 1 |
| pb_mask = ((1 as base.u64) << this.pb) - 1 |
| |
| // "outer" is the core loop discussed in README.md's "Algorithm Overview". |
| pos_end = pos ~sat+ this.decoded_length |
| while.outer pos < pos_end { |
| // AlgOve00 if decodeTheNextBym() == 0 |
| index_ao00 = (state << 4) | ((pos & pb_mask) as base.u32) |
| prob = this.probs_ao00[index_ao00] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_ao00[index_ao00] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve01 // Decode a LITERAL. |
| // AlgOve02 literal = decodeLiteral() |
| |
| index_lit = 15 & ( |
| (((pos & lp_mask) as base.u32) << lc) | |
| ((prev_byte as base.u32) >> (8 - lc))) |
| tree_node = 1 |
| |
| if state >= 7 { |
| assert tree_node < 0x100 |
| |
| while true, |
| pre tree_node < 0x100, |
| { |
| match_bit = (match_byte >> 7) as base.u32 |
| match_byte ~mod<<= 1 |
| prob = this.probs_lit[index_lit][0x100 + (match_bit << 8) + tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_lit[index_lit][0x100 + (match_bit << 8) + tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| if (tree_node >= 0x100) or (match_bit <> 0) { |
| break |
| } |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_lit[index_lit][0x100 + (match_bit << 8) + tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| if (tree_node >= 0x100) or (match_bit == 0) { |
| break |
| } |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } |
| |
| while tree_node < 0x100 { |
| prob = this.probs_lit[index_lit][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_lit[index_lit][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_lit[index_lit][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| |
| // AlgOve03 emitLiteral(literal) |
| // AlgOve04 continue |
| prev_byte = (tree_node & 0xFF) as base.u8 |
| args.dst.write_u8?(a: prev_byte) |
| pos ~mod+= 1 |
| state = STATE_TRANSITION_LITERAL[state] as base.u32 |
| continue.outer |
| } |
| |
| // AlgOve00a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_ao00[index_ao00] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| while.goto_do_the_lz_copy true, |
| post len >= 1, |
| {{ |
| // AlgOve20 if decodeTheNextBym() == 0 |
| prob = this.probs_ao20[state] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_ao20[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve21 // Decode a MATCH. |
| |
| while.goto_have_len true, |
| post len >= 1, |
| {{ |
| // AlgOve22 len = decodeLen() |
| |
| // AlgOve22.0 if decodeTheNextBym() == 0 |
| prob = this.probs_match_len_low[0][0] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_match_len_low[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve22.1 // Decode a low length. |
| // AlgOve22.2 len = decodeMultipleByms(3) + 2 |
| index_len = (pos & pb_mask) as base.u32 |
| tree_node = 1 |
| while tree_node < 0x08 { |
| prob = this.probs_match_len_low[index_len][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_match_len_low[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_match_len_low[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| len_state = CLAMP_NO_MORE_THAN_3[tree_node & 0x07] as base.u32 |
| len = (tree_node & 0x07) + 2 |
| assert len >= 1 |
| break.goto_have_len // goto AlgOve23. |
| } |
| |
| // AlgOve22.0a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_match_len_low[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve22.3 if decodeTheNextBym() == 0 |
| prob = this.probs_match_len_mid[0][0] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_match_len_mid[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve22.4 // Decode a middle length. |
| // AlgOve22.5 len = decodeMultipleByms(3) + 10 |
| index_len = (pos & pb_mask) as base.u32 |
| tree_node = 1 |
| while tree_node < 0x08 { |
| prob = this.probs_match_len_mid[index_len][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_match_len_mid[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_match_len_mid[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| len = (tree_node & 0x07) + 10 |
| assert len >= 1 |
| len_state = 3 |
| break.goto_have_len // goto AlgOve23. |
| } |
| |
| // AlgOve22.3a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_match_len_mid[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve22.7 // Decode a high length. |
| // AlgOve22.8 len = decodeMultipleByms(8) + 18 |
| tree_node = 1 |
| while tree_node < 0x100 { |
| prob = this.probs_match_len_high[0][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_match_len_high[0][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_match_len_high[0][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| len = (tree_node & 0xFF) + 18 |
| assert len >= 1 |
| len_state = 3 |
| break.goto_have_len |
| }} endwhile.goto_have_len |
| |
| // AlgOve23 slot = decodeSlot(min(len-2, 3)) |
| slot = 1 |
| while slot < 0x40, |
| inv len >= 1, |
| { |
| prob = this.probs_slot[len_state][slot] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_slot[len_state][slot] = (prob & 0xFFFF) as base.u16 |
| slot = (slot << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_slot[len_state][slot] = (prob & 0xFFFF) as base.u16 |
| slot = (slot << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| slot &= 0x3F |
| |
| // AlgOve24 distBiasedBy1 = decodeDistBiasedBy1(slot) |
| rep = slot |
| if slot < 4 { |
| // No-op. |
| |
| } else if slot < 14 { |
| num_extra_bits = (slot >> 1) - 1 |
| rep = (2 | (slot & 1)) << num_extra_bits |
| |
| // Read num_extra_bits "xxxx" bits. |
| index_small_dist_base = rep ~mod- slot |
| index_small_dist_extra = 1 |
| dist_extra_bits = 0 |
| i = 0 |
| while i < num_extra_bits, |
| inv len >= 1, |
| { |
| assert i < 30 via "a < b: a < c; c <= b"(c: num_extra_bits) |
| index_small_dist = (index_small_dist_base ~mod+ index_small_dist_extra) & 127 |
| prob = this.probs_small_dist[index_small_dist] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_small_dist[index_small_dist] = (prob & 0xFFFF) as base.u16 |
| index_small_dist_extra = (index_small_dist_extra ~mod<< 1) |
| i += 1 |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_small_dist[index_small_dist] = (prob & 0xFFFF) as base.u16 |
| index_small_dist_extra = (index_small_dist_extra ~mod<< 1) | 1 |
| dist_extra_bits |= (1 as base.u32) << i |
| i += 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| rep ~mod+= dist_extra_bits |
| |
| } else { |
| num_extra_bits = (slot >> 1) - 1 |
| assert num_extra_bits >= 6 |
| assert num_extra_bits <= 30 |
| rep = (2 | (slot & 1)) << num_extra_bits |
| |
| // Read (num_extra_bits - 4) "yyyy" bits. |
| dist_extra_bits = 0 |
| while true, |
| pre num_extra_bits > 4, |
| inv len >= 1, |
| post num_extra_bits > 0, |
| post num_extra_bits <= 4, |
| { |
| range >>= 1 |
| bits ~mod-= range |
| high_bit_was_on = 0 ~mod- (bits >> 31) |
| bits ~mod+= range & high_bit_was_on |
| dist_extra_bits = (dist_extra_bits ~mod<< 1) | ((high_bit_was_on ~mod+ 1) & 1) |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| num_extra_bits -= 1 |
| if num_extra_bits <= 4 { |
| break |
| } |
| } endwhile |
| dist_extra_bits ~mod<<= 4 |
| |
| // Read 4 "zzzz" bits. |
| index_large_dist = 1 |
| while true, |
| pre num_extra_bits > 0, |
| pre num_extra_bits <= 4, |
| inv len >= 1, |
| { |
| prob = this.probs_large_dist[index_large_dist] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_large_dist[index_large_dist] = (prob & 0xFFFF) as base.u16 |
| index_large_dist = 15 & ((index_large_dist ~mod<< 1)) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_large_dist[index_large_dist] = (prob & 0xFFFF) as base.u16 |
| index_large_dist = 15 & ((index_large_dist ~mod<< 1) | 1) |
| dist_extra_bits |= (1 as base.u32) << (4 - num_extra_bits) |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| num_extra_bits -= 1 |
| if num_extra_bits <= 0 { |
| break |
| } |
| } endwhile |
| rep ~mod+= dist_extra_bits |
| } |
| |
| // AlgOve25 if distBiasedBy1 == 0xFFFF_FFFF |
| if rep >= 0xFFFF_FFFF { |
| // AlgOve26 break |
| break.outer |
| } |
| |
| // AlgOve28 mrud = (1 + distBiasedBy1, mrud[0], mrud[1], mrud[2]) |
| rep3 = rep2 |
| rep2 = rep1 |
| rep1 = rep0 |
| rep0 = rep |
| |
| assert len >= 1 |
| state = STATE_TRANSITION_MATCH[state] as base.u32 |
| break.goto_do_the_lz_copy // goto AlgOve90. |
| } |
| |
| // AlgOve20a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_ao20[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve40 if decodeTheNextBym() == 0 |
| prob = this.probs_ao40[state] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_ao40[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve41 if decodeTheNextBym() == 0 |
| index_ao41 = (state << 4) | ((pos & pb_mask) as base.u32) |
| prob = this.probs_ao41[index_ao41] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_ao41[index_ao41] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve42 // Decode a SHORTREP. |
| // AlgOve43 len = 1 |
| len = 1 |
| |
| assert len >= 1 |
| state = STATE_TRANSITION_SHORTREP[state] as base.u32 |
| break.goto_do_the_lz_copy // goto AlgOve90. |
| } |
| |
| // AlgOve41a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_ao41[index_ao41] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve46 // Decode a LONGREP[0]. |
| |
| } else { |
| // AlgOve40a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_ao40[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve60 if decodeTheNextBym() == 0 |
| prob = this.probs_ao60[state] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_ao60[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve61 // Decode a LONGREP[1]. |
| // AlgOve62 mrud = (mrud[1], mrud[0], mrud[2], mrud[3]) |
| reptmp = rep1 |
| rep1 = rep0 |
| rep0 = reptmp |
| |
| } else { |
| // AlgOve60a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_ao60[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve63 if decodeTheNextBym() == 0 |
| prob = this.probs_ao63[state] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_ao63[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve64 // Decode a LONGREP[2]. |
| // AlgOve65 mrud = (mrud[2], mrud[0], mrud[1], mrud[3]) |
| reptmp = rep2 |
| rep2 = rep1 |
| rep1 = rep0 |
| rep0 = reptmp |
| |
| } else { |
| // AlgOve63a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_ao63[state] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve67 // Decode a LONGREP[3]. |
| // AlgOve68 mrud = (mrud[3], mrud[0], mrud[1], mrud[2]) |
| reptmp = rep3 |
| rep3 = rep2 |
| rep2 = rep1 |
| rep1 = rep0 |
| rep0 = reptmp |
| } |
| } |
| } |
| |
| // AlgOve80 len = decodeLen() |
| while.goto_after_decode_len true, |
| post len >= 1, |
| {{ |
| // AlgOve80.0 if decodeTheNextBym() == 0 |
| prob = this.probs_longrep_len_low[0][0] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_longrep_len_low[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve80.1 // Decode a low length. |
| // AlgOve80.2 len = decodeMultipleByms(3) + 2 |
| index_len = (pos & pb_mask) as base.u32 |
| tree_node = 1 |
| while tree_node < 0x08 { |
| prob = this.probs_longrep_len_low[index_len][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_longrep_len_low[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_longrep_len_low[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| len = (tree_node & 0x07) + 2 |
| assert len >= 1 |
| state = STATE_TRANSITION_LONGREP[state] as base.u32 |
| break.goto_after_decode_len |
| } |
| |
| // AlgOve80.0a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_longrep_len_low[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve80.3 if decodeTheNextBym() == 0 |
| prob = this.probs_longrep_len_mid[0][0] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_longrep_len_mid[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve80.4 // Decode a middle length. |
| // AlgOve80.5 len = decodeMultipleByms(3) + 10 |
| index_len = (pos & pb_mask) as base.u32 |
| tree_node = 1 |
| while tree_node < 0x08 { |
| prob = this.probs_longrep_len_mid[index_len][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_longrep_len_mid[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_longrep_len_mid[index_len][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| len = (tree_node & 0x07) + 10 |
| assert len >= 1 |
| state = STATE_TRANSITION_LONGREP[state] as base.u32 |
| break.goto_after_decode_len |
| } |
| |
| // AlgOve80.3a if decodeTheNextBym() == 0 // If-false branch. |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_longrep_len_mid[0][0] = (prob & 0xFFFF) as base.u16 |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| |
| // AlgOve80.7 // Decode a high length. |
| // AlgOve80.8 len = decodeMultipleByms(8) + 18 |
| tree_node = 1 |
| while tree_node < 0x100 { |
| prob = this.probs_longrep_len_high[0][tree_node] as base.u32 |
| threshold = (range >> 11) ~mod* prob |
| if bits < threshold { |
| range = threshold |
| prob ~mod+= (2048 ~mod- prob) >> 5 |
| this.probs_longrep_len_high[0][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) |
| } else { |
| bits ~mod-= threshold |
| range ~mod-= threshold |
| prob ~mod-= prob >> 5 |
| this.probs_longrep_len_high[0][tree_node] = (prob & 0xFFFF) as base.u16 |
| tree_node = (tree_node << 1) | 1 |
| } |
| if (range >> 24) == 0 { |
| c8 = args.src.read_u8?() |
| bits = (bits ~mod<< 8) | (c8 as base.u32) |
| range ~mod<<= 8 |
| } |
| } endwhile |
| len = (tree_node & 0xFF) + 18 |
| assert len >= 1 |
| state = STATE_TRANSITION_LONGREP[state] as base.u32 |
| |
| break.goto_after_decode_len |
| }} endwhile.goto_after_decode_len |
| break.goto_do_the_lz_copy |
| }} endwhile.goto_do_the_lz_copy |
| |
| // AlgOve90 labelDoTheLZCopy: |
| // AlgOve94 emitCopy(len, mrud[0]) |
| |
| assert len >= 1 |
| dist = rep0 + 1 |
| assert dist >= 1 |
| if ((dist as base.u64) > pos) or |
| ((dist as base.u64) > (this.dict_size as base.u64)) { |
| return "#bad distance" |
| } |
| pos ~mod+= len as base.u64 |
| // 274 is at least (len + 1). A limited_copy_u32_from_slice call below |
| // passes "up_to: len + 1". It's simpler if it's always a full copy. |
| while 274 > args.dst.length(), |
| inv len >= 1, |
| inv dist >= 1, |
| post 274 <= args.dst.length(), |
| { |
| yield? base."$short write" |
| } endwhile |
| assert (len as base.u64) <= args.dst.length() via "a <= b: a <= c; c <= b"(c: 274) |
| |
| // Copy from the args.workbuf history, if necessary. |
| if (dist as base.u64) > args.dst.history_length() { |
| adj_dist = (((dist as base.u64) - args.dst.history_length()) & 0xFFFF_FFFF) as base.u32 |
| if adj_dist > this.dict_seen { |
| return "#bad distance" |
| } |
| wb_index = (this.dict_workbuf_index as base.u64) ~mod- (adj_dist as base.u64) |
| while wb_index >= 0x8000_0000_0000_0000, |
| inv dist >= 1, |
| { |
| wb_index ~mod+= this.dict_size as base.u64 |
| } endwhile |
| if wb_index >= args.workbuf.length() { |
| return "#internal error: inconsistent dictionary state" |
| } |
| |
| if len < adj_dist { |
| // Copy len bytes of history and one more byte for the later |
| // half of the two-byte cusp, all from args.workbuf. |
| args.dst.limited_copy_u32_from_slice!(up_to: len + 1, s: args.workbuf[wb_index ..]) |
| if not args.dst.can_undo_byte() { |
| return "#internal error: inconsistent dictionary state" |
| } |
| match_byte = args.dst.peek_undo_byte() |
| args.dst.undo_byte!() |
| if not args.dst.can_undo_byte() { |
| return "#internal error: inconsistent dictionary state" |
| } |
| prev_byte = args.dst.peek_undo_byte() |
| continue.outer |
| } else if len == adj_dist { |
| // Like above, copy len bytes of history and one more byte for |
| // the later half of the two-byte cusp, but the copy-source |
| // crosses over from args.workbuf to args.dst. |
| args.dst.limited_copy_u32_from_slice!(up_to: len, s: args.workbuf[wb_index ..]) |
| args.dst.limited_copy_u32_from_history!(up_to: 1, distance: dist) |
| if not args.dst.can_undo_byte() { |
| return "#internal error: inconsistent dictionary state" |
| } |
| match_byte = args.dst.peek_undo_byte() |
| args.dst.undo_byte!() |
| if not args.dst.can_undo_byte() { |
| return "#internal error: inconsistent dictionary state" |
| } |
| prev_byte = args.dst.peek_undo_byte() |
| continue.outer |
| } |
| args.dst.limited_copy_u32_from_slice!(up_to: adj_dist, s: args.workbuf[wb_index ..]) |
| len -= adj_dist |
| assert len >= 1 |
| if ((len as base.u64) > args.dst.length()) or |
| ((dist as base.u64) > args.dst.history_length()) { |
| return "#internal error: inconsistent dictionary state" |
| } |
| } |
| |
| // Copy from the args.dst history. |
| assert len >= 1 |
| assert dist >= 1 |
| assert (len as base.u64) <= args.dst.length() |
| assert (dist as base.u64) <= args.dst.history_length() |
| match_cusp = args.dst.limited_copy_u32_from_history_fast_return_cusp!( |
| up_to: len, distance: dist) |
| match_byte = (match_cusp >> 8) as base.u8 |
| prev_byte = (match_cusp & 0xFF) as base.u8 |
| } endwhile.outer |
| |
| if bits <> 0 { |
| return "#bad bitstream trailer" |
| } else if (this.decoded_length <> 0xFFFF_FFFF_FFFF_FFFF) and (pos <> pos_end) { |
| return "#bad decoded length" |
| } |
| |
| this.stashed_bytes[0] = prev_byte |
| this.stashed_bytes[1] = match_byte |
| this.stashed_bits = bits |
| this.stashed_range = range |
| this.stashed_state = state |
| this.stashed_rep0 = rep0 |
| this.stashed_rep1 = rep1 |
| this.stashed_rep2 = rep2 |
| this.stashed_rep3 = rep3 |
| this.stashed_pos = pos |
| } |