use super::{u24::u24, ReadError, ReadExt as _};
use std::{
fmt::{Debug, Display},
io::{self, BufRead, Seek},
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("reading `LastInSequenceFlag` failed")]
LastInSequenceFlagReadData(#[source] io::Error),
#[error("`LastInSequenceFlag` : '{value:02x}' is not a valid value")]
LastInSequenceFlagInvalidValue { value: u8 },
#[error("`LastInSequenceFlag`::'{0}' flag is not mananged")]
LastInSequenceFlagNotManaged(LastInSequenceFlag),
#[error("skipping `Object ID` and `Object Version Number`")]
SkipObjectIdAndVerNum(#[source] ReadError),
#[error("read `Object Data Length` field")]
ReadObjectDataLength(#[source] io::Error),
#[error("read With of the image incarried by the `Object Definition Segment`(s)")]
ReadWidth(#[source] io::Error),
#[error("read Height of the image incarried by the `Object Definition Segment`(s)")]
ReadHeight(#[source] io::Error),
#[error("try reading object data (buffer slice size: {buff_size})")]
ObjectData {
#[source]
source: io::Error,
buff_size: usize,
},
}
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum LastInSequenceFlag {
Last = 0x40,
First = 0x80,
FirstAndLast = 0xC0,
}
impl TryFrom<u8> for LastInSequenceFlag {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x40 => Ok(Self::Last),
0x80 => Ok(Self::First),
0xC0 => Ok(Self::FirstAndLast),
value => Err(Error::LastInSequenceFlagInvalidValue { value }),
}
}
}
impl From<LastInSequenceFlag> for u8 {
fn from(val: LastInSequenceFlag) -> Self {
val as Self
}
}
impl From<LastInSequenceFlag> for &'static str {
fn from(val: LastInSequenceFlag) -> Self {
match val {
LastInSequenceFlag::Last => "Last",
LastInSequenceFlag::First => "First",
LastInSequenceFlag::FirstAndLast => "First and last",
}
}
}
impl Debug for LastInSequenceFlag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hex: u8 = (*self).into();
write!(f, "{hex:#02x}-{self}")
}
}
impl Display for LastInSequenceFlag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let friendly: &str = (*self).into();
write!(f, "{friendly} in sequence")
}
}
impl LastInSequenceFlag {
fn read<Reader: BufRead + Seek>(reader: &mut Reader) -> Result<Self, Error> {
let mut last_in_sequence_byte = [0];
reader
.read_exact(&mut last_in_sequence_byte)
.map_err(Error::LastInSequenceFlagReadData)?;
Self::try_from(last_in_sequence_byte[0])
}
}
#[derive(Debug)]
pub enum ObjectDefinitionSegment {
Partial {
data: ObjectDefinitionSegmentData,
amount_of_data_read: usize,
},
Complete(ObjectDefinitionSegmentData),
}
#[derive(Debug)] pub struct ObjectDefinitionSegmentData {
pub width: u16,
pub height: u16,
pub object_data: Vec<u8>,
}
pub fn read<Reader: BufRead + Seek>(
reader: &mut Reader,
segments_size: usize,
current_ods: Option<ObjectDefinitionSegment>,
) -> Result<ObjectDefinitionSegment, Error> {
handle_object_fields(reader)?;
let last_in_sequence_flag = LastInSequenceFlag::read(reader)?;
match current_ods {
None => {
assert!(
last_in_sequence_flag == LastInSequenceFlag::First
|| last_in_sequence_flag == LastInSequenceFlag::FirstAndLast
);
let data_size = read_obj_data_length(reader)?;
let (width, height) = read_img_size(reader)?;
let data_size = data_size - 4; let mut object_data = vec![0; data_size];
let read_data_size = segments_size - 11; let data_buff = &mut object_data.as_mut_slice()[0..read_data_size];
read_object_data(reader, data_buff)?;
let data = ObjectDefinitionSegmentData {
width,
height,
object_data,
};
if last_in_sequence_flag == LastInSequenceFlag::FirstAndLast {
assert!(read_data_size == data_size);
assert!(segments_size == 11 + data_size);
Ok(ObjectDefinitionSegment::Complete(data))
} else if last_in_sequence_flag == LastInSequenceFlag::First {
Ok(ObjectDefinitionSegment::Partial {
data,
amount_of_data_read: read_data_size,
})
} else {
Err(Error::LastInSequenceFlagNotManaged(last_in_sequence_flag))
}
}
Some(ObjectDefinitionSegment::Partial {
mut data,
amount_of_data_read,
}) => {
assert!(last_in_sequence_flag == LastInSequenceFlag::Last);
let start_idx = amount_of_data_read;
let end_idx = start_idx + (segments_size - 4);
let read_slice = &mut data.object_data.as_mut_slice()[start_idx..end_idx];
read_object_data(reader, read_slice)?;
Ok(ObjectDefinitionSegment::Complete(data))
}
Some(ObjectDefinitionSegment::Complete(_)) => {
panic!("read shouln'd be called with a `Complete` `ObjectDefinitionSegment`");
}
}
}
fn handle_object_fields<Reader: BufRead + Seek>(reader: &mut Reader) -> Result<(), Error> {
reader
.skip_data(2 + 1)
.map_err(Error::SkipObjectIdAndVerNum)?;
Ok(())
}
fn read_obj_data_length<Reader: BufRead + Seek>(reader: &mut Reader) -> Result<usize, Error> {
let mut buffer = [0; 3];
reader
.read_exact(&mut buffer)
.map_err(Error::ReadObjectDataLength)?;
let object_data_length = u24::from(<&[u8] as TryInto<[u8; 3]>>::try_into(&buffer).unwrap());
Ok(object_data_length.to_u32().try_into().unwrap())
}
fn read_img_size<Reader: BufRead + Seek>(reader: &mut Reader) -> Result<(u16, u16), Error> {
let mut buffer = [0; 2];
reader.read_exact(&mut buffer).map_err(Error::ReadWidth)?;
let width = u16::from_be_bytes(buffer);
reader.read_exact(&mut buffer).map_err(Error::ReadHeight)?;
let height = u16::from_be_bytes(buffer);
Ok((width, height))
}
fn read_object_data<Reader: BufRead + Seek>(
reader: &mut Reader,
data_buff: &mut [u8],
) -> Result<(), Error> {
reader
.read_exact(data_buff)
.map_err(|source| Error::ObjectData {
source,
buff_size: data_buff.len(),
})
}