blob: da7a15c4c5e4a4b8310f09afdaccccbd165b34ea [file] [log] [blame]
// Copyright 2024 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
pri func decoder.decode_huffman_groups?(src: base.io_reader, n_huffman_groups: base.u32[..= 256]) {
var hg : base.u32
var ht : base.u32
hg = 0
while hg < args.n_huffman_groups {
assert hg < 256 via "a < b: a < c; c <= b"(c: args.n_huffman_groups)
ht = 0
while ht < 5,
inv hg < 256,
{
this.decode_huffman_tree?(src: args.src, hg: hg, ht: ht)
ht += 1
}
hg += 1
}
}
pri func decoder.decode_huffman_tree?(src: base.io_reader, hg: base.u32[..= 255], ht: base.u32[..= 4]) {
var c8 : base.u8
var use_simple : base.u32[..= 1]
var status : base.status
if args.ht >= 4 {
this.ht_n_symbols = 40
} else if args.ht > 0 {
this.ht_n_symbols = 256
} else if this.color_cache_bits == 0 {
this.ht_n_symbols = 280
} else {
this.ht_n_symbols = 280 + ((1 as base.u32) << this.color_cache_bits)
}
if this.n_bits < 1 {
c8 = args.src.read_u8?()
this.bits = (c8 as base.u32)
this.n_bits = 8
assert this.n_bits >= 1
}
use_simple = this.bits & 1
this.bits >>= 1
this.n_bits -= 1
if use_simple <> 0 {
this.decode_huffman_tree_simple?(src: args.src, hg: args.hg, ht: args.ht)
} else {
this.decode_code_length_code_lengths?(src: args.src)
status = this.build_code_lengths_huffman_nodes!()
if not status.is_ok() {
return status
}
this.build_code_lengths?(src: args.src)
status = this.build_huffman_nodes!(hg: args.hg, ht: args.ht)
if not status.is_ok() {
return status
}
}
}
pri func decoder.decode_huffman_tree_simple?(src: base.io_reader, hg: base.u32[..= 255], ht: base.u32[..= 4]) {
var c8 : base.u8
var use_second_symbol : base.u32[..= 1]
var first_symbol_n_bits : base.u32[..= 8]
var symbol0 : base.u32[..= 0xFF]
var symbol1 : base.u32[..= 0xFF]
var base_offset : base.u32[..= 0x064C]
if this.n_bits < 2 {
c8 = args.src.read_u8?()
if this.n_bits >= 2 {
return "#internal error: inconsistent n_bits"
}
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 2
}
use_second_symbol = this.bits & 1
first_symbol_n_bits = (((this.bits & 2) >> 1) * 7) + 1
this.bits >>= 2
this.n_bits -= 2
if this.n_bits < first_symbol_n_bits {
c8 = args.src.read_u8?()
if this.n_bits >= first_symbol_n_bits {
return "#internal error: inconsistent n_bits"
}
assert this.n_bits < 8 via "a < b: a < c; c <= b"(c: first_symbol_n_bits)
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 8
assert first_symbol_n_bits <= this.n_bits via "a <= b: a <= c; c <= b"(c: 8)
assert this.n_bits >= first_symbol_n_bits via "a >= b: b <= a"()
}
symbol0 = this.bits & (((1 as base.u32) << first_symbol_n_bits) - 1)
this.bits >>= first_symbol_n_bits
this.n_bits -= first_symbol_n_bits
base_offset = HUFFMAN_TABLE_BASE_OFFSETS[args.ht] as base.u32
if use_second_symbol <> 0 {
if this.n_bits < 8 {
c8 = args.src.read_u8?()
if this.n_bits >= 8 {
return "#internal error: inconsistent n_bits"
}
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 8
}
symbol1 = this.bits & 0xFF
this.bits >>= 8
this.n_bits -= 8
this.huffman_nodes[args.hg][base_offset + 0] = (base_offset + 1) as base.u16
this.huffman_nodes[args.hg][base_offset + 1] = (symbol0 | 0x8000) as base.u16
this.huffman_nodes[args.hg][base_offset + 2] = (symbol1 | 0x8000) as base.u16
} else {
this.huffman_nodes[args.hg][base_offset] = (symbol0 | 0x8000) as base.u16
}
}
pri func decoder.decode_code_length_code_lengths?(src: base.io_reader) {
var c8 : base.u8
var n_codes : base.u32[..= 19]
var i : base.u32
if this.n_bits < 4 {
c8 = args.src.read_u8?()
if this.n_bits >= 4 {
return "#internal error: inconsistent n_bits"
}
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 4
}
n_codes = (this.bits & 15) + 4
this.bits >>= 4
this.n_bits -= 4
i = 0
while i < n_codes {
assert i < 19 via "a < b: a < c; c <= b"(c: n_codes)
if this.n_bits < 3 {
c8 = args.src.read_u8?()
if this.n_bits >= 3 {
return "#internal error: inconsistent n_bits"
}
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 3
}
this.code_length_code_lengths[CODE_LENGTH_CODE_ORDER[i]] = (this.bits & 7) as base.u8
this.bits >>= 3
this.n_bits -= 3
i += 1
}
while i < 19 {
this.code_length_code_lengths[CODE_LENGTH_CODE_ORDER[i]] = 0
i += 1
}
}
pri func decoder.build_code_lengths_huffman_nodes!() base.status {
var code_bits : base.u32
var code_len : base.u32[..= 7] // The "code length code length".
var symbol : base.u32[..= 19] // The "code length or 16, 17, 18".
var histogram : array[8] base.u32
var n_used_symbols : base.u32
var last_used_symbol : base.u32[..= 18]
var subscription_weight : base.u32[..= 0x8000]
var subscription_total : base.u32
var curr_code : base.u32
var next_codes : array[9] base.u32
var n_branches : base.u32
var h : base.u32[..= 36]
var children : base.u32
var node : base.u16
symbol = 0
while symbol < 19 {
code_len = this.code_length_code_lengths[symbol] as base.u32
if code_len <> 0 {
histogram[code_len] ~mod+= 1
n_used_symbols ~mod+= 1
last_used_symbol = symbol
}
symbol += 1
}
if n_used_symbols < 1 {
return "#bad Huffman code"
} else if n_used_symbols == 1 {
this.code_lengths_huffman_nodes[0] = (last_used_symbol | 0x8000) as base.u16
return ok
}
subscription_weight = 1 << 14
code_len = 1
while true {
curr_code = (curr_code ~mod+ histogram[code_len]) ~mod<< 1
next_codes[code_len + 1] = curr_code
subscription_total ~mod+= subscription_weight ~mod* histogram[code_len]
subscription_weight >>= 1
if code_len >= 7 {
break
}
code_len += 1
}
if subscription_total > (1 << 15) {
return "#bad Huffman code (over-subscribed)"
} else if subscription_total < (1 << 15) {
return "#bad Huffman code (under-subscribed)"
}
this.code_lengths_huffman_nodes[0] = 0
symbol = 0
while symbol < 19 {
code_len = this.code_length_code_lengths[symbol] as base.u32
if code_len > 0 {
code_bits = next_codes[code_len]
next_codes[code_len] ~mod+= 1
// Insert {symbol, code_bits, code_len} into the node tree.
code_bits ~mod<<= 32 - code_len
h = 0
while code_len > 0,
inv symbol < 19,
{
node = this.code_lengths_huffman_nodes[h]
if node == 0 {
children = 1 ~mod+ (2 ~mod* n_branches)
children = children.min(no_more_than: 35)
this.code_lengths_huffman_nodes[h] = children as base.u16
this.code_lengths_huffman_nodes[children + 0] = 0
this.code_lengths_huffman_nodes[children + 1] = 0
h = children + (code_bits >> 31)
n_branches ~mod+= 1
} else {
children = node as base.u32
h = children.min(no_more_than: 35) + (code_bits >> 31)
}
code_bits ~mod<<= 1
code_len -= 1
}
this.code_lengths_huffman_nodes[h] = (symbol | 0x8000) as base.u16
}
symbol += 1
}
return ok
}
pri func decoder.build_huffman_nodes!(hg: base.u32[..= 255], ht: base.u32[..= 4]) base.status {
var base_offset : base.u32[..= 0x064C]
var code_bits : base.u32
var code_len : base.u32[..= 15]
var symbol : base.u32[..= 2328]
var histogram : array[16] base.u32
var n_used_symbols : base.u32
var last_used_symbol : base.u32[..= 2328]
var subscription_weight : base.u32[..= 0x8000]
var subscription_total : base.u32
var curr_code : base.u32
var next_codes : array[17] base.u32
var n_branches : base.u32
var h : base.u32[..= 0x187A]
var children : base.u32
var node : base.u16
base_offset = HUFFMAN_TABLE_BASE_OFFSETS[args.ht] as base.u32
symbol = 0
while symbol < this.ht_n_symbols {
assert symbol < 2328 via "a < b: a < c; c <= b"(c: this.ht_n_symbols)
code_len = (this.code_lengths[symbol] & 15) as base.u32
if code_len <> 0 {
histogram[code_len] ~mod+= 1
n_used_symbols ~mod+= 1
last_used_symbol = symbol
}
symbol += 1
}
if n_used_symbols < 1 {
return "#bad Huffman code"
} else if n_used_symbols == 1 {
this.huffman_nodes[args.hg][base_offset] = (last_used_symbol | 0x8000) as base.u16
return ok
}
subscription_weight = 1 << 14
code_len = 1
while true {
curr_code = (curr_code ~mod+ histogram[code_len]) ~mod<< 1
next_codes[code_len + 1] = curr_code
subscription_total ~mod+= subscription_weight ~mod* histogram[code_len]
subscription_weight >>= 1
if code_len >= 15 {
break
}
code_len += 1
}
if subscription_total > (1 << 15) {
return "#bad Huffman code (over-subscribed)"
} else if subscription_total < (1 << 15) {
return "#bad Huffman code (under-subscribed)"
}
this.huffman_nodes[args.hg][base_offset] = 0
symbol = 0
while symbol < this.ht_n_symbols {
assert symbol < 2328 via "a < b: a < c; c <= b"(c: this.ht_n_symbols)
code_len = (this.code_lengths[symbol] & 15) as base.u32
if code_len <> 0 {
code_bits = next_codes[code_len]
next_codes[code_len] ~mod+= 1
// Insert {symbol, code_bits, code_len} into the node tree.
code_bits ~mod<<= 32 - code_len
h = base_offset
while code_len > 0,
inv symbol < 2328,
{
node = this.huffman_nodes[args.hg][h]
if node == 0 {
children = base_offset ~mod+ (1 ~mod+ (2 ~mod* n_branches))
children = children.min(no_more_than: 0x1879)
this.huffman_nodes[args.hg][h] = children as base.u16
this.huffman_nodes[args.hg][children + 0] = 0
this.huffman_nodes[args.hg][children + 1] = 0
h = children + (code_bits >> 31)
n_branches ~mod+= 1
} else {
children = node as base.u32
h = children.min(no_more_than: 0x1879) + (code_bits >> 31)
}
code_bits ~mod<<= 1
code_len -= 1
}
this.huffman_nodes[args.hg][h] = (symbol | 0x8000) as base.u16
}
symbol += 1
}
return ok
}
pri func decoder.build_code_lengths?(src: base.io_reader) {
var c8 : base.u8
var use_length : base.u32[..= 1]
var length_n_bits : base.u32[..= 16]
var length : base.u32[..= 65537]
var prev_code_length : base.u16[..= 15]
var h : base.u32[..= 36]
var s : base.u32[..= 2328]
var s_max : base.u32
var node : base.u16
var symbol : base.u32[..= 0x7FFF]
var repeat_value : base.u16[..= 15]
var repeat_n_bits : base.u32[..= 7]
if this.n_bits < 1 {
c8 = args.src.read_u8?()
this.bits = (c8 as base.u32)
this.n_bits = 8
assert this.n_bits >= 1
}
use_length = this.bits & 1
this.bits >>= 1
this.n_bits -= 1
this.ht_code_lengths_remaining = this.ht_n_symbols
if use_length <> 0 {
if this.n_bits < 3 {
c8 = args.src.read_u8?()
if this.n_bits >= 3 {
return "#internal error: inconsistent n_bits"
}
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 3
}
length_n_bits = ((this.bits & 7) * 2) + 2
this.bits >>= 3
this.n_bits -= 3
while this.n_bits < length_n_bits,
post this.n_bits >= length_n_bits,
{
c8 = args.src.read_u8?()
if this.n_bits >= length_n_bits {
return "#internal error: inconsistent n_bits"
}
assert this.n_bits < 16 via "a < b: a < c; c <= b"(c: length_n_bits)
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
}
length = (this.bits & (((1 as base.u32) << length_n_bits) - 1)) + 2
this.bits >>= length_n_bits
this.n_bits -= length_n_bits
if length > this.ht_n_symbols {
return "#bad Huffman code"
}
this.ht_code_lengths_remaining = length
}
prev_code_length = 8
while s < this.ht_n_symbols {
assert s < 2328 via "a < b: a < c; c <= b"(c: this.ht_n_symbols)
if this.ht_code_lengths_remaining <= 0 {
while s < this.ht_n_symbols {
assert s < 2328 via "a < b: a < c; c <= b"(c: this.ht_n_symbols)
this.code_lengths[s] = 0
s += 1
}
break
}
this.ht_code_lengths_remaining -= 1
h = 0
while true,
inv s < 2328,
{
node = this.code_lengths_huffman_nodes[h]
if node >= 0x8000 {
break
} else if node > 35 {
return "#internal error: inconsistent Huffman code"
}
if this.n_bits < 1 {
c8 = args.src.read_u8?()
this.bits = (c8 as base.u32)
this.n_bits = 8
assert this.n_bits >= 1
}
h = (node as base.u32) + (this.bits & 1)
this.bits >>= 1
this.n_bits -= 1
}
symbol = (node & 0x7FFF) as base.u32
if symbol == 0 {
this.code_lengths[s] = 0
s += 1
continue
} else if symbol < 16 {
prev_code_length = symbol as base.u16
this.code_lengths[s] = prev_code_length
s += 1
continue
} else if symbol == 16 {
repeat_value = prev_code_length
} else {
repeat_value = 0
}
repeat_n_bits = REPEAT_N_BITS[symbol & 3] as base.u32
s_max = (REPEAT_COUNTS[symbol & 3] as base.u32) ~mod+ s
if this.n_bits < repeat_n_bits {
c8 = args.src.read_u8?()
if this.n_bits >= repeat_n_bits {
return "#internal error: inconsistent n_bits"
}
assert this.n_bits < 7 via "a < b: a < c; c <= b"(c: repeat_n_bits)
this.bits |= (c8 as base.u32) << this.n_bits
this.n_bits += 8
assert this.n_bits >= 8
assert repeat_n_bits <= this.n_bits via "a <= b: a <= c; c <= b"(c: 8)
assert this.n_bits >= repeat_n_bits via "a >= b: b <= a"()
}
s_max ~mod+= this.bits & (((1 as base.u32) << repeat_n_bits) - 1)
this.bits >>= repeat_n_bits
this.n_bits -= repeat_n_bits
if s_max > this.ht_n_symbols {
return "#bad Huffman code"
}
assert s_max <= 2328 via "a <= b: a <= c; c <= b"(c: this.ht_n_symbols)
while s < s_max,
inv s_max <= 2328,
{
assert s < 2328 via "a < b: a < c; c <= b"(c: s_max)
this.code_lengths[s] = repeat_value
s += 1
}
}
}
pri const CODE_LENGTH_CODE_ORDER : roarray[19] base.u8[..= 18] = [
17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
]
pri const REPEAT_N_BITS : roarray[4] base.u8[..= 7] = [2, 3, 7, 0]
pri const REPEAT_COUNTS : roarray[4] base.u8[..= 11] = [3, 3, 11, 0]
// See the decoder.huffman_nodes comment re five (5) Huffman trees.
pri const HUFFMAN_TABLE_BASE_OFFSETS : roarray[5] base.u16[..= 0x064C] = [
0x064C,
0x0000,
0x01FF,
0x03FE,
0x05FD,
]