use super::{Jp2Error, Jp2Result};
#[derive(Clone, Copy)]
pub(crate) struct MqState {
pub(crate) qe: u16,
pub(crate) nmps: u8,
pub(crate) nlps: u8,
pub(crate) sw: u8,
}
pub(crate) static MQ_TABLE: [MqState; 47] = [
MqState {
qe: 0x5601,
nmps: 1,
nlps: 1,
sw: 1,
}, MqState {
qe: 0x3401,
nmps: 2,
nlps: 6,
sw: 0,
}, MqState {
qe: 0x1801,
nmps: 3,
nlps: 9,
sw: 0,
}, MqState {
qe: 0x0AC1,
nmps: 4,
nlps: 12,
sw: 0,
}, MqState {
qe: 0x0521,
nmps: 5,
nlps: 29,
sw: 0,
}, MqState {
qe: 0x0221,
nmps: 38,
nlps: 33,
sw: 0,
}, MqState {
qe: 0x5601,
nmps: 7,
nlps: 6,
sw: 1,
}, MqState {
qe: 0x5401,
nmps: 8,
nlps: 14,
sw: 0,
}, MqState {
qe: 0x4801,
nmps: 9,
nlps: 14,
sw: 0,
}, MqState {
qe: 0x3801,
nmps: 10,
nlps: 14,
sw: 0,
}, MqState {
qe: 0x3001,
nmps: 11,
nlps: 17,
sw: 0,
}, MqState {
qe: 0x2401,
nmps: 12,
nlps: 18,
sw: 0,
}, MqState {
qe: 0x1C01,
nmps: 13,
nlps: 20,
sw: 0,
}, MqState {
qe: 0x1601,
nmps: 29,
nlps: 21,
sw: 0,
}, MqState {
qe: 0x5601,
nmps: 15,
nlps: 14,
sw: 1,
}, MqState {
qe: 0x5401,
nmps: 16,
nlps: 14,
sw: 0,
}, MqState {
qe: 0x5101,
nmps: 17,
nlps: 15,
sw: 0,
}, MqState {
qe: 0x4801,
nmps: 18,
nlps: 16,
sw: 0,
}, MqState {
qe: 0x3801,
nmps: 19,
nlps: 17,
sw: 0,
}, MqState {
qe: 0x3401,
nmps: 20,
nlps: 18,
sw: 0,
}, MqState {
qe: 0x3001,
nmps: 21,
nlps: 19,
sw: 0,
}, MqState {
qe: 0x2801,
nmps: 22,
nlps: 19,
sw: 0,
}, MqState {
qe: 0x2401,
nmps: 23,
nlps: 20,
sw: 0,
}, MqState {
qe: 0x2201,
nmps: 24,
nlps: 21,
sw: 0,
}, MqState {
qe: 0x1C01,
nmps: 25,
nlps: 22,
sw: 0,
}, MqState {
qe: 0x1801,
nmps: 26,
nlps: 23,
sw: 0,
}, MqState {
qe: 0x1601,
nmps: 27,
nlps: 24,
sw: 0,
}, MqState {
qe: 0x1401,
nmps: 28,
nlps: 25,
sw: 0,
}, MqState {
qe: 0x1201,
nmps: 29,
nlps: 26,
sw: 0,
}, MqState {
qe: 0x1101,
nmps: 30,
nlps: 27,
sw: 0,
}, MqState {
qe: 0x0AC1,
nmps: 31,
nlps: 28,
sw: 0,
}, MqState {
qe: 0x09C1,
nmps: 32,
nlps: 29,
sw: 0,
}, MqState {
qe: 0x08A1,
nmps: 33,
nlps: 30,
sw: 0,
}, MqState {
qe: 0x0521,
nmps: 34,
nlps: 31,
sw: 0,
}, MqState {
qe: 0x0441,
nmps: 35,
nlps: 32,
sw: 0,
}, MqState {
qe: 0x02A1,
nmps: 36,
nlps: 33,
sw: 0,
}, MqState {
qe: 0x0221,
nmps: 37,
nlps: 34,
sw: 0,
}, MqState {
qe: 0x0141,
nmps: 38,
nlps: 35,
sw: 0,
}, MqState {
qe: 0x0111,
nmps: 39,
nlps: 36,
sw: 0,
}, MqState {
qe: 0x0085,
nmps: 40,
nlps: 37,
sw: 0,
}, MqState {
qe: 0x0049,
nmps: 41,
nlps: 38,
sw: 0,
}, MqState {
qe: 0x0025,
nmps: 42,
nlps: 39,
sw: 0,
}, MqState {
qe: 0x0015,
nmps: 43,
nlps: 40,
sw: 0,
}, MqState {
qe: 0x0009,
nmps: 44,
nlps: 41,
sw: 0,
}, MqState {
qe: 0x0005,
nmps: 45,
nlps: 42,
sw: 0,
}, MqState {
qe: 0x0001,
nmps: 45,
nlps: 43,
sw: 0,
}, MqState {
qe: 0x5601,
nmps: 46,
nlps: 46,
sw: 0,
}, ];
pub const MQ_NUM_CONTEXTS: usize = 19;
pub struct MqDecoder {
a: u32,
c: u32,
ct: u8,
buf: Vec<u8>,
pos: usize,
cx_mps: [u8; MQ_NUM_CONTEXTS],
cx_state: [u8; MQ_NUM_CONTEXTS],
}
impl MqDecoder {
pub fn new(data: &[u8]) -> Self {
let buf = data.to_vec();
let mut mq = Self {
a: 0x8000,
c: 0,
ct: 0,
buf,
pos: 0,
cx_mps: [0u8; MQ_NUM_CONTEXTS],
cx_state: [0u8; MQ_NUM_CONTEXTS],
};
let b0 = mq.next_byte();
mq.c = u32::from(b0) << 16;
mq.byte_in();
mq.c <<= 7;
mq.ct = mq.ct.wrapping_sub(7);
mq.a = 0x8000;
mq
}
fn next_byte(&mut self) -> u8 {
if self.pos < self.buf.len() {
let b = self.buf[self.pos];
self.pos += 1;
b
} else {
self.pos += 1;
0xFF
}
}
fn byte_in(&mut self) {
let prev = if self.pos >= 1 && self.pos - 1 < self.buf.len() {
self.buf[self.pos - 1]
} else {
0xFF
};
if prev == 0xFF {
let next = if self.pos < self.buf.len() {
self.buf[self.pos]
} else {
0xFF
};
if next > 0x8F {
self.c += 0xFF00;
self.ct = 8;
} else {
let b = self.next_byte();
self.c += u32::from(b) << 9;
self.ct = 7;
}
} else {
let b = self.next_byte();
self.c += u32::from(b) << 8;
self.ct = 8;
}
}
pub fn decode_bit(&mut self, cx: usize) -> Jp2Result<u8> {
if cx >= MQ_NUM_CONTEXTS {
return Err(Jp2Error::InternalError(format!(
"MQ context index {cx} out of range (max {})",
MQ_NUM_CONTEXTS - 1
)));
}
let entry = MQ_TABLE[usize::from(self.cx_state[cx])];
let qe = u32::from(entry.qe);
self.a = self.a.wrapping_sub(qe);
let symbol;
if (self.c >> 16) < qe {
symbol = self.lps_exchange(cx, qe, &entry);
self.renorm_d();
} else {
self.c -= qe << 16;
if self.a & 0x8000 == 0 {
symbol = self.mps_exchange(cx, qe, &entry);
self.renorm_d();
} else {
symbol = self.cx_mps[cx];
}
}
Ok(symbol)
}
fn mps_exchange(&mut self, cx: usize, qe: u32, entry: &MqState) -> u8 {
if self.a < qe {
let d = 1 - self.cx_mps[cx];
if entry.sw == 1 {
self.cx_mps[cx] = 1 - self.cx_mps[cx];
}
self.cx_state[cx] = entry.nlps;
d
} else {
self.cx_state[cx] = entry.nmps;
self.cx_mps[cx]
}
}
fn lps_exchange(&mut self, cx: usize, qe: u32, entry: &MqState) -> u8 {
let d;
if self.a < qe {
d = self.cx_mps[cx];
self.cx_state[cx] = entry.nmps;
} else {
d = 1 - self.cx_mps[cx];
if entry.sw == 1 {
self.cx_mps[cx] = 1 - self.cx_mps[cx];
}
self.cx_state[cx] = entry.nlps;
}
self.a = qe;
d
}
fn renorm_d(&mut self) {
loop {
if self.ct == 0 {
self.byte_in();
}
self.a <<= 1;
self.c <<= 1;
self.ct -= 1;
if self.a & 0x8000 != 0 {
break;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mq_table_length() {
assert_eq!(MQ_TABLE.len(), 47);
}
#[test]
fn mq_initial_state_is_zero() {
let data = vec![0x00u8; 16];
let mq = MqDecoder::new(&data);
assert_eq!(mq.a, 0x8000);
for &s in &mq.cx_state {
assert_eq!(s, 0);
}
for &m in &mq.cx_mps {
assert_eq!(m, 0);
}
}
#[test]
fn mq_decode_all_zeros_stream() {
let data = vec![0x00u8; 32];
let mut mq = MqDecoder::new(&data);
for _ in 0..10 {
let bit = mq.decode_bit(0).expect("decode");
assert!(bit == 0 || bit == 1);
}
}
#[test]
fn mq_decode_known_sequence() {
let data: Vec<u8> = (0u8..=30).collect();
let mut mq = MqDecoder::new(&data);
let mut results = Vec::new();
for _ in 0..10 {
match mq.decode_bit(0) {
Ok(bit) => results.push(bit),
Err(_) => break,
}
}
for &b in &results {
assert!(b == 0 || b == 1, "MQ bit must be 0 or 1, got {b}");
}
}
}