use crate::error::{Jpeg2000Error, Result};
pub const NUM_CONTEXTS: usize = 19;
pub mod ctx {
pub const SIG_LL_LH_START: usize = 0;
pub const SIG_HL_START: usize = 0;
pub const SIG_HH_START: usize = 0;
pub const SIGN_START: usize = 9;
pub const MAG_REF_START: usize = 14;
pub const RUN_LENGTH: usize = 17;
pub const UNIFORM: usize = 18;
pub const AGGREGATION: usize = 17;
}
#[derive(Debug, Clone, Copy)]
struct QeEntry {
qe: u16,
next_mps: u8,
next_lps: u8,
switch_flag: bool,
}
const QE_TABLE: [QeEntry; 47] = [
QeEntry {
qe: 0x5601,
next_mps: 1,
next_lps: 1,
switch_flag: true,
}, QeEntry {
qe: 0x3401,
next_mps: 2,
next_lps: 6,
switch_flag: false,
}, QeEntry {
qe: 0x1801,
next_mps: 3,
next_lps: 9,
switch_flag: false,
}, QeEntry {
qe: 0x0AC1,
next_mps: 4,
next_lps: 12,
switch_flag: false,
}, QeEntry {
qe: 0x0521,
next_mps: 5,
next_lps: 29,
switch_flag: false,
}, QeEntry {
qe: 0x0221,
next_mps: 38,
next_lps: 33,
switch_flag: false,
}, QeEntry {
qe: 0x5601,
next_mps: 7,
next_lps: 6,
switch_flag: true,
}, QeEntry {
qe: 0x5401,
next_mps: 8,
next_lps: 14,
switch_flag: false,
}, QeEntry {
qe: 0x4801,
next_mps: 9,
next_lps: 14,
switch_flag: false,
}, QeEntry {
qe: 0x3801,
next_mps: 10,
next_lps: 14,
switch_flag: false,
}, QeEntry {
qe: 0x3001,
next_mps: 11,
next_lps: 17,
switch_flag: false,
}, QeEntry {
qe: 0x2401,
next_mps: 12,
next_lps: 18,
switch_flag: false,
}, QeEntry {
qe: 0x1C01,
next_mps: 13,
next_lps: 20,
switch_flag: false,
}, QeEntry {
qe: 0x1601,
next_mps: 29,
next_lps: 21,
switch_flag: false,
}, QeEntry {
qe: 0x5601,
next_mps: 15,
next_lps: 14,
switch_flag: true,
}, QeEntry {
qe: 0x5401,
next_mps: 16,
next_lps: 14,
switch_flag: false,
}, QeEntry {
qe: 0x5101,
next_mps: 17,
next_lps: 15,
switch_flag: false,
}, QeEntry {
qe: 0x4801,
next_mps: 18,
next_lps: 16,
switch_flag: false,
}, QeEntry {
qe: 0x3801,
next_mps: 19,
next_lps: 17,
switch_flag: false,
}, QeEntry {
qe: 0x3401,
next_mps: 20,
next_lps: 18,
switch_flag: false,
}, QeEntry {
qe: 0x3001,
next_mps: 21,
next_lps: 19,
switch_flag: false,
}, QeEntry {
qe: 0x2801,
next_mps: 22,
next_lps: 19,
switch_flag: false,
}, QeEntry {
qe: 0x2401,
next_mps: 23,
next_lps: 20,
switch_flag: false,
}, QeEntry {
qe: 0x2201,
next_mps: 24,
next_lps: 21,
switch_flag: false,
}, QeEntry {
qe: 0x1C01,
next_mps: 25,
next_lps: 22,
switch_flag: false,
}, QeEntry {
qe: 0x1801,
next_mps: 26,
next_lps: 23,
switch_flag: false,
}, QeEntry {
qe: 0x1601,
next_mps: 27,
next_lps: 24,
switch_flag: false,
}, QeEntry {
qe: 0x1401,
next_mps: 28,
next_lps: 25,
switch_flag: false,
}, QeEntry {
qe: 0x1201,
next_mps: 29,
next_lps: 26,
switch_flag: false,
}, QeEntry {
qe: 0x1101,
next_mps: 30,
next_lps: 27,
switch_flag: false,
}, QeEntry {
qe: 0x0AC1,
next_mps: 31,
next_lps: 28,
switch_flag: false,
}, QeEntry {
qe: 0x09C1,
next_mps: 32,
next_lps: 29,
switch_flag: false,
}, QeEntry {
qe: 0x08A1,
next_mps: 33,
next_lps: 30,
switch_flag: false,
}, QeEntry {
qe: 0x0521,
next_mps: 34,
next_lps: 31,
switch_flag: false,
}, QeEntry {
qe: 0x0441,
next_mps: 35,
next_lps: 32,
switch_flag: false,
}, QeEntry {
qe: 0x02A1,
next_mps: 36,
next_lps: 33,
switch_flag: false,
}, QeEntry {
qe: 0x0221,
next_mps: 37,
next_lps: 34,
switch_flag: false,
}, QeEntry {
qe: 0x0141,
next_mps: 38,
next_lps: 35,
switch_flag: false,
}, QeEntry {
qe: 0x0111,
next_mps: 39,
next_lps: 36,
switch_flag: false,
}, QeEntry {
qe: 0x0085,
next_mps: 40,
next_lps: 37,
switch_flag: false,
}, QeEntry {
qe: 0x0049,
next_mps: 41,
next_lps: 38,
switch_flag: false,
}, QeEntry {
qe: 0x0025,
next_mps: 42,
next_lps: 39,
switch_flag: false,
}, QeEntry {
qe: 0x0015,
next_mps: 43,
next_lps: 40,
switch_flag: false,
}, QeEntry {
qe: 0x0009,
next_mps: 44,
next_lps: 41,
switch_flag: false,
}, QeEntry {
qe: 0x0005,
next_mps: 45,
next_lps: 42,
switch_flag: false,
}, QeEntry {
qe: 0x0001,
next_mps: 45,
next_lps: 43,
switch_flag: false,
}, QeEntry {
qe: 0x5601,
next_mps: 46,
next_lps: 46,
switch_flag: false,
}, ];
#[derive(Debug, Clone, Copy, Default)]
pub struct MqContextState {
qe_index: u8,
mps: u8,
}
#[derive(Debug, Clone)]
pub struct MqDecoder {
buffer: Vec<u8>,
position: usize,
c_register: u32,
a_register: u32,
ct: u32,
t_bar: u8,
contexts: [MqContextState; NUM_CONTEXTS],
exhausted: bool,
}
impl MqDecoder {
pub fn new(data: Vec<u8>) -> Self {
let mut decoder = Self {
buffer: data,
position: 0,
c_register: 0,
a_register: 0x8000,
ct: 0,
t_bar: 0,
contexts: [MqContextState::default(); NUM_CONTEXTS],
exhausted: false,
};
decoder.init_contexts();
decoder.init_dec();
decoder
}
fn init_contexts(&mut self) {
for ctx in &mut self.contexts {
ctx.qe_index = 0;
ctx.mps = 0;
}
self.contexts[ctx::UNIFORM].qe_index = 46;
self.contexts[ctx::UNIFORM].mps = 0;
self.contexts[ctx::RUN_LENGTH].qe_index = 3;
self.contexts[ctx::RUN_LENGTH].mps = 0;
}
fn init_dec(&mut self) {
self.t_bar = if !self.buffer.is_empty() {
let b = self.buffer[0];
self.position = 1;
b
} else {
0xFF
};
self.c_register = (u32::from(self.t_bar) ^ 0xFF) << 16;
self.byte_in();
self.c_register <<= 7;
self.ct = self.ct.saturating_sub(7);
self.a_register = 0x8000;
}
fn byte_in(&mut self) {
if self.t_bar == 0xFF {
if self.position < self.buffer.len() {
let next = self.buffer[self.position];
self.position += 1;
if next > 0x8F {
self.position -= 1; self.c_register += 0xFF00;
self.ct = 8;
self.exhausted = true;
} else {
self.t_bar = next;
self.c_register += u32::from(self.t_bar) << 9;
self.ct = 7;
}
} else {
self.c_register += 0xFF00;
self.ct = 8;
self.exhausted = true;
}
} else {
if self.position < self.buffer.len() {
self.t_bar = self.buffer[self.position];
self.position += 1;
self.c_register += u32::from(self.t_bar) << 8;
self.ct = 8;
} else {
self.t_bar = 0xFF;
self.c_register += 0xFF00;
self.ct = 8;
self.exhausted = true;
}
}
}
fn renorm_d(&mut self) {
loop {
if self.ct == 0 {
self.byte_in();
}
self.a_register <<= 1;
self.c_register <<= 1;
self.ct = self.ct.saturating_sub(1);
if self.a_register >= 0x8000 {
break;
}
}
}
pub fn decode(&mut self, context_id: usize) -> Result<u8> {
if context_id >= NUM_CONTEXTS {
return Err(Jpeg2000Error::Tier1Error(format!(
"Invalid MQ context ID: {} (max {})",
context_id,
NUM_CONTEXTS - 1
)));
}
let ctx = self.contexts[context_id];
let qe_entry = QE_TABLE[ctx.qe_index as usize];
let qe = u32::from(qe_entry.qe);
self.a_register = self.a_register.wrapping_sub(qe);
let symbol;
if (self.c_register >> 16) < self.a_register {
if self.a_register < 0x8000 {
symbol = self.mps_exchange(context_id, &qe_entry);
self.renorm_d();
} else {
symbol = ctx.mps;
}
} else {
self.c_register = self.c_register.wrapping_sub(self.a_register << 16);
symbol = self.lps_exchange(context_id, &qe_entry);
self.renorm_d();
}
Ok(symbol)
}
fn mps_exchange(&mut self, context_id: usize, entry: &QeEntry) -> u8 {
let qe = u32::from(entry.qe);
let mps = self.contexts[context_id].mps;
if self.a_register < qe {
let d = 1 - mps;
if entry.switch_flag {
self.contexts[context_id].mps = 1 - mps;
}
self.contexts[context_id].qe_index = entry.next_lps;
self.a_register = qe;
d
} else {
self.contexts[context_id].qe_index = entry.next_mps;
mps
}
}
fn lps_exchange(&mut self, context_id: usize, entry: &QeEntry) -> u8 {
let qe = u32::from(entry.qe);
let mps = self.contexts[context_id].mps;
if self.a_register < qe {
self.a_register = qe;
self.contexts[context_id].qe_index = entry.next_mps;
mps
} else {
let d = 1 - mps;
self.a_register = qe;
if entry.switch_flag {
self.contexts[context_id].mps = 1 - mps;
}
self.contexts[context_id].qe_index = entry.next_lps;
d
}
}
pub fn decode_raw(&mut self) -> Result<u8> {
if self.ct == 0 {
self.byte_in();
}
self.ct = self.ct.saturating_sub(1);
let bit = ((self.c_register >> (16 + self.ct)) & 1) as u8;
Ok(bit)
}
pub fn is_exhausted(&self) -> bool {
self.exhausted
}
pub fn bytes_consumed(&self) -> usize {
self.position
}
pub fn reset_context(&mut self, context_id: usize) {
if context_id < NUM_CONTEXTS {
self.contexts[context_id] = MqContextState::default();
if context_id == ctx::UNIFORM {
self.contexts[context_id].qe_index = 46;
} else if context_id == ctx::RUN_LENGTH {
self.contexts[context_id].qe_index = 3;
}
}
}
pub fn reset_all_contexts(&mut self) {
self.init_contexts();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mq_decoder_creation() {
let data = vec![0x80, 0x40, 0x55, 0x00, 0x12, 0x34, 0x56, 0x78];
let decoder = MqDecoder::new(data);
assert!(!decoder.is_exhausted());
assert_eq!(decoder.a_register, 0x8000);
}
#[test]
fn test_mq_decoder_empty_data() {
let decoder = MqDecoder::new(vec![]);
assert!(decoder.is_exhausted());
}
#[test]
fn test_mq_decode_symbol() {
let data = vec![0x00, 0x00, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78];
let mut decoder = MqDecoder::new(data);
let result = decoder.decode(0);
assert!(result.is_ok());
let bit = result.expect("decode failed");
assert!(bit <= 1);
}
#[test]
fn test_mq_decode_multiple_symbols() {
let data = vec![
0x80, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xAA, 0x55, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC,
0xDE, 0xF0,
];
let mut decoder = MqDecoder::new(data);
for ctx_id in 0..NUM_CONTEXTS {
let result = decoder.decode(ctx_id);
assert!(result.is_ok(), "Failed to decode from context {}", ctx_id);
}
}
#[test]
fn test_mq_invalid_context() {
let data = vec![0x00, 0x00, 0x00, 0x01];
let mut decoder = MqDecoder::new(data);
let result = decoder.decode(NUM_CONTEXTS);
assert!(result.is_err());
}
#[test]
fn test_mq_decode_raw() {
let data = vec![0xAA, 0x55, 0xFF, 0x00, 0x12, 0x34, 0x56, 0x78];
let mut decoder = MqDecoder::new(data);
for _ in 0..8 {
let result = decoder.decode_raw();
assert!(result.is_ok());
let bit = result.expect("raw decode failed");
assert!(bit <= 1);
}
}
#[test]
fn test_mq_context_reset() {
let data = vec![0x80, 0x00, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78];
let mut decoder = MqDecoder::new(data);
let _ = decoder.decode(0);
let _ = decoder.decode(0);
decoder.reset_context(0);
assert_eq!(decoder.contexts[0].qe_index, 0);
assert_eq!(decoder.contexts[0].mps, 0);
}
#[test]
fn test_mq_uniform_context_init() {
let data = vec![0x00, 0x01, 0x02, 0x03];
let decoder = MqDecoder::new(data);
assert_eq!(decoder.contexts[ctx::UNIFORM].qe_index, 46);
}
#[test]
fn test_mq_run_length_context_init() {
let data = vec![0x00, 0x01, 0x02, 0x03];
let decoder = MqDecoder::new(data);
assert_eq!(decoder.contexts[ctx::RUN_LENGTH].qe_index, 3);
}
#[test]
fn test_mq_byte_stuffing_marker() {
let data = vec![0xFF, 0x90, 0x00, 0x01];
let mut decoder = MqDecoder::new(data);
let result = decoder.decode(0);
assert!(result.is_ok());
}
#[test]
fn test_mq_byte_stuffing_non_marker() {
let data = vec![0xFF, 0x00, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC];
let mut decoder = MqDecoder::new(data);
let result = decoder.decode(0);
assert!(result.is_ok());
}
#[test]
fn test_qe_table_valid() {
for (i, entry) in QE_TABLE.iter().enumerate() {
assert!(
(entry.next_mps as usize) < QE_TABLE.len(),
"Invalid next_mps at index {}: {}",
i,
entry.next_mps
);
assert!(
(entry.next_lps as usize) < QE_TABLE.len(),
"Invalid next_lps at index {}: {}",
i,
entry.next_lps
);
}
}
#[test]
fn test_mq_reset_all_contexts() {
let data = vec![0x80, 0x00, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78];
let mut decoder = MqDecoder::new(data);
let _ = decoder.decode(0);
let _ = decoder.decode(5);
let _ = decoder.decode(10);
decoder.reset_all_contexts();
assert_eq!(decoder.contexts[ctx::UNIFORM].qe_index, 46);
assert_eq!(decoder.contexts[ctx::RUN_LENGTH].qe_index, 3);
for i in 0..9 {
assert_eq!(decoder.contexts[i].qe_index, 0);
}
}
}