use std::rc::Rc;
use crate::{pgs_memory_buffer::{BigEndian, ReadBytes}, Error, PgsMemoryBuffer, PgsSegmentHeader, Result};
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum PgsOdsSequenceFlag {
Unknown,
First,
Last,
Both,
}
impl From<u8> for PgsOdsSequenceFlag {
fn from(value: u8) -> Self {
match value {
0x40 => PgsOdsSequenceFlag::Last,
0x80 => PgsOdsSequenceFlag::First,
0xC0 => PgsOdsSequenceFlag::Both,
_ => PgsOdsSequenceFlag::Unknown
}
}
}
#[derive(Debug)]
pub struct PgsOdsSegment {
pub header: PgsSegmentHeader,
pub object_id: u16,
pub object_version_number: u8,
pub last_in_sequence_flag: PgsOdsSequenceFlag,
pub object_data_length: u32,
pub width: u16,
pub height: u16,
pub object_data: Vec<u8>
}
impl PgsOdsSegment {
fn new(header: PgsSegmentHeader) -> Self {
PgsOdsSegment {
header,
object_id: 0,
object_version_number: 0,
last_in_sequence_flag: PgsOdsSequenceFlag::Unknown,
object_data_length: 0,
width: 0,
height: 0,
object_data: Vec::new()
}
}
pub fn from_data(header: PgsSegmentHeader, data: &[u8]) -> Result<Rc<PgsOdsSegment>> {
if data.len() < header.segment_length as usize {
return Err(Error::InvalidSegmentDataLength);
}
let mut segment = PgsOdsSegment::new(header);
let mut buffer: PgsMemoryBuffer = PgsMemoryBuffer::from(data);
segment.object_id = buffer.read_u16::<BigEndian>()?;
segment.object_version_number = buffer.read_u8()?;
segment.last_in_sequence_flag = PgsOdsSequenceFlag::from(buffer.read_u8()?);
segment.object_data_length = buffer.read_u24::<BigEndian>()? - 4;
let (width, height) = if segment.last_in_sequence_flag == PgsOdsSequenceFlag::First || segment.last_in_sequence_flag == PgsOdsSequenceFlag::Both {
let width = buffer.read_u16::<BigEndian>()?;
let height = buffer.read_u16::<BigEndian>()?;
(width, height)
} else {
(0, 0)
};
segment.width = width;
segment.height = height;
segment.object_data = buffer.read_into_vec(segment.object_data_length)?;
Ok(Rc::new(segment))
}
}