blob: 33b21d26d71beafc82cce7171bfc5f790f6fc712 [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.flush_block?(dst: base.io_writer) {
var i : base.u32[..= 1_048575]
var n : base.u32
var entry : base.u32
var repeat_count : base.u32[..= 255]
var block_checksum_have : base.u32
var prev : base.u8
var curr : base.u8
if this.original_pointer >= this.block_size {
return "#bad block length"
}
assert this.original_pointer < 900000 via "a < b: a < c; c <= b"(c: this.block_size)
i = this.bwt[this.original_pointer] >> 12
block_checksum_have = 0xFFFF_FFFF
n = 0
while n < this.block_size {
assert n < 900000 via "a < b: a < c; c <= b"(c: this.block_size)
entry = this.bwt[i]
curr = (entry & 0xFF) as base.u8
i = entry >> 12
if repeat_count >= 4 {
repeat_count = curr as base.u32
while repeat_count > 0,
inv n < 900000,
{
block_checksum_have =
REV_CRC32_TABLE[((block_checksum_have >> 24) as base.u8) ^ prev] ^
(block_checksum_have ~mod<< 8)
args.dst.write_u8?(a: prev)
repeat_count -= 1
} endwhile
repeat_count = 0
} else if curr <> prev {
repeat_count = 1
block_checksum_have =
REV_CRC32_TABLE[((block_checksum_have >> 24) as base.u8) ^ curr] ^
(block_checksum_have ~mod<< 8)
args.dst.write_u8?(a: curr)
} else {
repeat_count += 1
block_checksum_have =
REV_CRC32_TABLE[((block_checksum_have >> 24) as base.u8) ^ curr] ^
(block_checksum_have ~mod<< 8)
args.dst.write_u8?(a: curr)
}
prev = curr
n += 1
} endwhile
block_checksum_have ^= 0xFFFF_FFFF
if block_checksum_have <> this.block_checksum_want {
return "#bad checksum"
}
this.final_checksum_have = block_checksum_have ^ (
(this.final_checksum_have >> 31) |
(this.final_checksum_have ~mod<< 1))
}