use super::bitreader::J2kBitReader;
use super::{Jp2Error, Jp2Result};
#[derive(Debug, Clone)]
pub struct PacketHeader {
pub included_blocks: Vec<bool>,
pub data_lengths: Vec<usize>,
}
struct TagTree {
values: Vec<i32>,
num_leaves: usize,
depth: usize,
leaf_width: usize,
}
impl TagTree {
fn new(num_blocks: usize) -> Self {
if num_blocks == 0 {
return Self {
values: Vec::new(),
num_leaves: 0,
depth: 0,
leaf_width: 0,
};
}
let leaf_width = num_blocks.next_power_of_two();
let depth = leaf_width.trailing_zeros() as usize + 1;
let total_nodes = leaf_width * 2;
Self {
values: vec![0; total_nodes],
num_leaves: num_blocks,
depth,
leaf_width,
}
}
fn decode_threshold(
&mut self,
reader: &mut J2kBitReader,
leaf_idx: usize,
threshold: i32,
) -> Jp2Result<bool> {
if leaf_idx >= self.num_leaves {
return Ok(false);
}
if self.leaf_width == 0 {
return Ok(false);
}
let bit = reader.read_bit()?;
let included = bit != 0;
if leaf_idx + self.leaf_width < self.values.len() {
self.values[leaf_idx + self.leaf_width] = if included { 0 } else { 1 };
}
Ok(included && 0 < threshold)
}
}
fn decode_block_length(reader: &mut J2kBitReader) -> Jp2Result<usize> {
let mut num_passes = 1usize;
let pass_bit = reader.read_bit()?;
if pass_bit == 1 {
let pass_bit2 = reader.read_bit()?;
if pass_bit2 == 1 {
let v = reader.read_bits(2)?;
num_passes = 3 + v as usize;
} else {
num_passes = 2;
}
}
let lblock: u8 = 3;
let mut extra_bits = 0u8;
loop {
let b = reader.read_bit()?;
if b == 0 {
break;
}
extra_bits += 1;
if extra_bits >= 30 {
return Err(Jp2Error::InternalError(
"excessive length prefix bits in Tier-2 packet header".to_string(),
));
}
}
let total_bits = lblock + extra_bits;
if total_bits > 30 {
return Err(Jp2Error::InternalError(
"length bits exceeds 30 in Tier-2 packet header".to_string(),
));
}
let length = reader.read_bits(total_bits)? as usize;
let _ = num_passes; Ok(length)
}
pub fn parse_packet_header(
reader: &mut J2kBitReader,
num_blocks: usize,
) -> Jp2Result<PacketHeader> {
let mut included_blocks = vec![false; num_blocks];
let mut data_lengths = vec![0usize; num_blocks];
let not_empty = reader.read_bit()?;
if not_empty == 0 {
return Ok(PacketHeader {
included_blocks,
data_lengths,
});
}
let mut incl_tree = TagTree::new(num_blocks);
let zbp_tree = TagTree::new(num_blocks);
for block_idx in 0..num_blocks {
let included = incl_tree.decode_threshold(reader, block_idx, 1)?;
included_blocks[block_idx] = included;
if included {
let mut _zbp = 0u32;
loop {
let bit = reader.read_bit()?;
if bit == 0 {
break;
}
_zbp += 1;
let _zbp_ref = zbp_tree.num_leaves;
if _zbp > 64 {
return Err(Jp2Error::InternalError(
"excessive zero bit-plane count in Tier-2".to_string(),
));
}
}
}
}
for block_idx in 0..num_blocks {
if included_blocks[block_idx] {
data_lengths[block_idx] = decode_block_length(reader)?;
}
}
Ok(PacketHeader {
included_blocks,
data_lengths,
})
}
pub fn parse_packet_header_bytes(
header_bytes: &[u8],
num_blocks: usize,
) -> Jp2Result<PacketHeader> {
let mut reader = J2kBitReader::new(header_bytes);
parse_packet_header(&mut reader, num_blocks)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_packet_returns_all_excluded() {
let data = [0x00u8]; let header = parse_packet_header_bytes(&data, 4).expect("parse");
assert_eq!(header.included_blocks.len(), 4);
assert!(header.included_blocks.iter().all(|&b| !b));
}
#[test]
fn zero_blocks_returns_empty() {
let data = [0x80u8]; let header = parse_packet_header_bytes(&data, 0).expect("parse");
assert_eq!(header.included_blocks.len(), 0);
assert_eq!(header.data_lengths.len(), 0);
}
#[test]
fn tag_tree_new_empty() {
let t = TagTree::new(0);
assert_eq!(t.num_leaves, 0);
}
#[test]
fn tag_tree_new_single() {
let t = TagTree::new(1);
assert_eq!(t.num_leaves, 1);
}
#[test]
fn parse_packet_does_not_panic_on_short_data() {
let data = [0x80u8]; let result = parse_packet_header_bytes(&data, 2);
let _ = result;
}
}