blob: fe65baadcd6faa2c8378a1905c0c2375109a30af [file] [log] [blame]
// Copyright 2022 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pri func decoder.decode_block_slow?(src: base.io_reader) {
var which : base.u8[..= 5]
var c : base.u8
var child : base.u16
var child_ff : base.u32[..= 255]
var i : base.u32
var j : base.u32
var ticks : base.u32[..= 50]
var section : base.u32
var bs : base.u32[..= 1_048575] // 1_048575 = ((1 << 20) - 1)
var output : base.u32[..= 255]
var node_index : base.u32[..= 1023]
var run_shift : base.u32[..= 23]
var run : base.u32[..= 16_777216] // 16_777216 = (2 << 23)
var mtft0 : base.u32[..= 255]
which = CLAMP_TO_5[this.huffman_selectors[0] & 7]
section = 1
// Initialize the MTFT state.
i = 0
j = 0
while i < 256 {
if this.presence[i] <> 0 {
this.mtft[j & 0xFF] = i as base.u8
j ~mod+= 1
}
i += 1
} endwhile
i = 0
while i < 256 {
this.letter_counts[i] = 0
i += 1
} endwhile
// Apply the Huffman trees.
ticks = 50
while.outer true {
if ticks > 0 {
ticks -= 1
} else {
ticks = 49
which = CLAMP_TO_5[this.huffman_selectors[section & 32767] & 7]
section ~mod+= 1
}
node_index = 0
while true {
if this.n_bits <= 0 {
c = args.src.read_u8?()
this.bits = (c as base.u32) << 24
this.n_bits = 8
assert this.n_bits > 0
}
child = this.huffman_trees[which][node_index][this.bits >> 31]
this.bits ~mod<<= 1
this.n_bits -= 1
if child < 1024 { // Branch node.
node_index = child as base.u32
continue
} else if child < 1280 { // mNN symbol.
// Move to front.
child_ff = (child & 0xFF) as base.u32
output = this.mtft[child_ff] as base.u32
this.mtft[1 .. 1 + child_ff].copy_from_slice!(
s: this.mtft[.. child_ff])
this.mtft[0] = output as base.u8
this.letter_counts[output] ~mod+= 1
this.bwt[bs] = output
if bs >= this.max_incl_block_size {
return "#bad block length"
}
assert bs < 900000 via "a < b: a < c; c <= b"(c: this.max_incl_block_size)
bs += 1
run_shift = 0
break
} else if child > 1281 { // EOB symbol.
break.outer
}
// RUNA or RUNB symbol.
if run_shift >= 23 {
return "#bad block length"
}
run = ((child - 1279) as base.u32) << run_shift
run_shift += 1
i = bs
j = run + bs
if j > this.max_incl_block_size {
return "#bad block length"
}
assert j <= 900000 via "a <= b: a <= c; c <= b"(c: this.max_incl_block_size)
bs = j
mtft0 = this.mtft[0] as base.u32
this.letter_counts[mtft0] ~mod+= run
while i < j,
pre j <= 900000,
{
assert i < 900000 via "a < b: a < c; c <= b"(c: j)
this.bwt[i] = mtft0
i += 1
} endwhile
break
} endwhile
} endwhile.outer
if bs > this.max_incl_block_size {
return "#bad block length"
}
assert bs <= 900000 via "a <= b: a <= c; c <= b"(c: this.max_incl_block_size)
this.block_size = bs
}