mod decoder;
mod idx;
mod img;
mod mpeg2;
mod palette;
mod probe;
mod sub;
pub use self::{
idx::{Index, TimePointIdx},
img::{conv_to_rgba, VobSubIndexedImage, VobSubOcrImage, VobSubToImage},
palette::{palette, palette_rgb_to_luminance, Palette},
probe::{is_idx_file, is_sub_file},
sub::{ErrorMissing, Sub},
};
use crate::content::ContentError;
use nom::{IResult, Needed};
use std::{fmt, io, path::PathBuf};
use thiserror::Error;
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum VobSubError {
#[error("error with data")]
Content(#[from] ContentError),
#[error("could not find required key '{0}'")]
MissingKey(&'static str),
#[error("failed to parse lang in idx file")]
LangParsing,
#[error("could not parse: {0}")]
Parse(String),
#[error("palette must have 16 entries, found '{0}' one")]
PaletteInvalidEntriesNumbers(usize),
#[error("error during palette parsing from .idx file")]
PaletteError(#[source] NomError),
#[error("invalid scan line offsets : start 0 {start_0}, start 1 {start_1}, end {end}")]
InvalidScanLineOffsets {
start_0: usize,
start_1: usize,
end: usize,
},
#[error("unexpected end of buffer while parsing 16-bit size")]
BufferTooSmallForU16,
#[error("unexpected end of subtitle data")]
UnexpectedEndOfSubtitleData,
#[error("error with Control sequence parsing")]
ControlSequence(#[source] NomError),
#[error("control offset value tried to leads backwards")]
ControlOffsetWentBackwards,
#[error("control offset is 0x{offset:x}, but packet is only 0x{packet:x} bytes")]
ControlOffsetBiggerThanPacket {
offset: usize,
packet: usize,
},
#[error("PES packet parsing.")]
PESPacket(#[source] NomError),
#[error("incomplete control packet")]
IncompleteControlPacket,
#[error("packet is too short")]
PacketTooShort,
#[error("found subtitle without timing into")]
MissingTimingForSubtitle,
#[error("missing during subtitle parsing")]
MissingSubtitleParsing(#[from] ErrorMissing),
#[error("could not process subtitle image")]
Image(#[from] img::Error),
#[error("Io error on '{path}'")]
Io {
source: io::Error,
path: PathBuf,
},
}
#[derive(Debug, Error)]
pub enum NomError {
#[error("unexpected extra input")]
UnexpectedInput,
#[error("incomplete input: '{0:?}' needed")]
IncompleteInput(Needed),
#[error("error from nom : {0}")]
Error(String),
#[error("failure from nom : {0}")]
Failure(String),
}
pub trait IResultExt<I, O, E> {
fn to_result_no_rest(self) -> Result<O, NomError>;
fn to_result(self) -> Result<(I, O), NomError>;
}
impl<I: Default + Eq, O, E: fmt::Debug> IResultExt<I, O, E> for IResult<I, O, E> {
fn to_result_no_rest(self) -> Result<O, NomError> {
match self {
Self::Ok((rest, val)) => {
if rest == I::default() {
Ok(val)
} else {
Err(NomError::UnexpectedInput)
}
}
Self::Err(err) => match err {
nom::Err::Incomplete(needed) => Err(NomError::IncompleteInput(needed)),
nom::Err::Error(err) => Err(NomError::Error(format!("{err:?}"))),
nom::Err::Failure(err) => Err(NomError::Failure(format!("{err:?}"))),
},
}
}
fn to_result(self) -> Result<(I, O), NomError> {
match self {
Self::Ok((rest, val)) => Ok((rest, val)),
Self::Err(err) => match err {
nom::Err::Incomplete(needed) => Err(NomError::IncompleteInput(needed)),
nom::Err::Error(err) => Err(NomError::Error(format!("{err:?}"))),
nom::Err::Failure(err) => Err(NomError::Failure(format!("{err:?}"))),
},
}
}
}