mod decoder;
mod ods;
mod pds;
mod pgs_image;
mod segment;
mod sup;
mod u24;
pub use decoder::{DecodeTimeImage, DecodeTimeOnly, PgsDecoder};
pub use pgs_image::{RleEncodedImage, RleToImage};
pub use sup::SupParser;
use self::segment::SegmentTypeCode;
use std::{
io::{self, BufRead, Seek},
num::TryFromIntError,
path::PathBuf,
};
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum PgsError {
#[error("Io error on '{path}'")]
Io {
source: io::Error,
path: PathBuf,
},
#[error("object Definition Segment parsing")]
ODSParse(#[from] ods::Error),
#[error("palette Definition Segment parsing")]
PDSParse(#[from] pds::Error),
#[error("invalid value '{value:#02x}' for Segment Type Code")]
SegmentInvalidTypeCode {
value: u8,
},
#[error("failed to read a complete segment header")]
SegmentFailReadHeader,
#[error("unable to read segment - PG missing!")]
SegmentPGMissing,
#[error("skipping Segment {type_code}")]
SegmentSkip {
#[source]
source: ReadError,
type_code: SegmentTypeCode,
},
#[error("missing image during `Presentation Graphic Stream (PGS)` parsing")]
MissingImage,
#[error("missing palette after image parsing")]
MissingPalette,
}
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum ReadError {
#[error("failed read buffer of size : {buffer_size}")]
FailedReadBuffer {
#[source]
source: io::Error,
buffer_size: usize,
},
#[error("failed to fill buffer from Reader")]
FailedFillBuf(#[source] io::Error),
#[error("seek failed")]
FailedSeek(#[source] io::Error),
#[error("invalid skip value: `{value}` can't be converted in valid seek offset (i64 number)")]
InvalidSeekValue {
#[source]
source: TryFromIntError,
value: usize,
},
}
pub trait ReadExt
where
Self: BufRead + Seek,
{
fn read_buffer(&mut self, to_read: &mut [u8]) -> Result<(), ReadError> {
self.read_exact(to_read)
.map_err(|source| ReadError::FailedReadBuffer {
source,
buffer_size: to_read.len(),
})
}
fn skip_data(&mut self, to_skip: usize) -> Result<(), ReadError> {
let buff = self.fill_buf().map_err(ReadError::FailedFillBuf)?;
if buff.len() >= to_skip {
self.consume(to_skip);
} else {
let to_skip = i64::try_from(to_skip).map_err(|source| ReadError::InvalidSeekValue {
source,
value: to_skip,
})?;
self.seek_relative(to_skip).map_err(ReadError::FailedSeek)?;
}
Ok(())
}
}
impl<U> ReadExt for U where U: BufRead + Seek {}