diff --git a/src/content/area.rs b/src/content/area.rs index 9e28c69..4fbcddd 100644 --- a/src/content/area.rs +++ b/src/content/area.rs @@ -1,5 +1,4 @@ -use super::Size; -use crate::SubError; +use super::{ContentError, Size}; /// Location at which to display the subtitle. #[derive(Debug, Clone, PartialEq, Eq)] @@ -53,7 +52,7 @@ impl Area { } impl TryFrom for Area { - type Error = SubError; + type Error = ContentError; fn try_from(coords_value: AreaValues) -> Result { // Check for weird bounding boxes. Ideally we @@ -63,7 +62,7 @@ impl TryFrom for Area { // have non-negative width and height and we'll // crash if they don't. if coords_value.x2 <= coords_value.x1 || coords_value.y2 <= coords_value.y1 { - Err(SubError::Parse("invalid bounding box".into())) + Err(Self::Error::InvalidAreaBounding) } else { Ok(Self(coords_value)) } diff --git a/src/content/mod.rs b/src/content/mod.rs index 3fee384..91c16dd 100644 --- a/src/content/mod.rs +++ b/src/content/mod.rs @@ -4,3 +4,13 @@ mod size; pub use area::{Area, AreaValues}; pub use size::Size; +use thiserror::Error; + +/// Error for content +#[derive(Debug, Error)] +pub enum ContentError { + /// Indicate an invalid bounding box Area + /// Example: If at least one coordinate value of second point are inferior of first point. + #[error("Invalid bounding box for Area")] + InvalidAreaBounding, +} diff --git a/src/errors.rs b/src/errors.rs index c1fdcae..3992876 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,7 +1,5 @@ //! Custom error types. -use std::io; -use std::path::PathBuf; use thiserror::Error; /// A type representing errors that are specific to `subtile`. Note that we may @@ -9,32 +7,7 @@ use thiserror::Error; /// kinds of errors from third-party libraries. #[derive(Debug, Error)] pub enum SubError { - /// Our input data ended sooner than we expected. - #[error("Input ended unexpectedly")] - IncompleteInput, - - /// We were unable to find a required key in an `*.idx` file. - #[error("Could not find required key '{0}'")] - MissingKey(&'static str), - - /// We could not parse a value. - #[error("Could not parse: {0}")] - Parse(String), - - /// We could not process a subtitle image. - #[error("Could not process subtitle image: {0}")] - Image(String), - - /// We have leftover input that we didn't expect. - #[error("Unexpected extra input")] - UnexpectedInput, - - /// We could not read a file. - #[error("Could not read '{path}'")] - Io { - /// Source error - source: io::Error, - /// Path of the file we tried to read - path: PathBuf, - }, + /// Error with `VobSub` + #[error("Error with VobSub")] + VobSub(#[from] crate::vobsub::VobSubError), } diff --git a/src/vobsub/idx.rs b/src/vobsub/idx.rs index c377820..01bafca 100644 --- a/src/vobsub/idx.rs +++ b/src/vobsub/idx.rs @@ -9,9 +9,7 @@ use std::io::prelude::*; use std::io::BufReader; use std::path::Path; -use super::{palette, sub, Palette}; -use crate::errors::SubError; -use crate::vobsub::IResultExt; +use super::{palette, sub, IResultExt, Palette, VobSubError}; /// A `*.idx` file describing the subtitles in a `*.sub` file. #[derive(Debug)] @@ -27,9 +25,9 @@ pub struct Index { impl Index { /// Open an `*.idx` file and the associated `*.sub` file. #[profiling::function] - pub fn open>(path: P) -> Result { + pub fn open>(path: P) -> Result { let path = path.as_ref(); - let mkerr_idx = |source| SubError::Io { + let mkerr_idx = |source| VobSubError::Io { source, path: path.into(), }; @@ -42,13 +40,13 @@ impl Index { sub_path.set_extension("sub"); let sub_path = sub_path.as_path(); - let mut sub = fs::File::open(sub_path).map_err(|source| SubError::Io { + let mut sub = fs::File::open(sub_path).map_err(|source| VobSubError::Io { source, path: sub_path.into(), })?; let mut sub_data = vec![]; sub.read_to_end(&mut sub_data) - .map_err(|source| SubError::Io { + .map_err(|source| VobSubError::Io { source, path: sub_path.into(), })?; @@ -77,10 +75,10 @@ impl Index { /// Read the palette in .idx file content #[profiling::function] -pub fn read_palette(mut input: BufReader, mkerr: &Err) -> Result +pub fn read_palette(mut input: BufReader, mkerr: &Err) -> Result where T: std::io::Read, - Err: Fn(io::Error) -> SubError, + Err: Fn(io::Error) -> VobSubError, { static KEY_VALUE: Lazy = Lazy::new(|| Regex::new("^([A-Za-z/ ]+): (.*)").unwrap()); @@ -93,7 +91,11 @@ where let val = cap.get(2).unwrap().as_str(); match key { "palette" => { - palette_val = Some(palette(val.as_bytes()).to_vobsub_result()?); + palette_val = Some( + palette(val.as_bytes()) + .to_result_no_rest() + .map_err(VobSubError::PaletteError)?, + ); } _ => trace!("Unimplemented idx key: {}", key), } @@ -101,7 +103,7 @@ where buf.clear(); } - let palette = palette_val.ok_or(SubError::MissingKey("palette"))?; + let palette = palette_val.ok_or(VobSubError::MissingKey("palette"))?; Ok(palette) } diff --git a/src/vobsub/img.rs b/src/vobsub/img.rs index 77b6ada..399aacd 100644 --- a/src/vobsub/img.rs +++ b/src/vobsub/img.rs @@ -11,7 +11,8 @@ use nom::{ }; use safemem::write_bytes; -use crate::{content::Size, util::BytesFormatter, SubError}; +use super::VobSubError; +use crate::{content::Size, util::BytesFormatter}; /// A run-length encoded value. #[derive(Debug)] @@ -47,7 +48,7 @@ fn rle(input: (&[u8], usize)) -> IResult<(&[u8], usize), Rle> { /// Decompress the scan-line `input` into `output`, returning the number of /// input bytes consumed. -fn scan_line(input: &[u8], output: &mut [u8]) -> Result { +fn scan_line(input: &[u8], output: &mut [u8]) -> Result { trace!("scan line starting with {:?}", BytesFormatter(input)); let width = output.len(); let mut x = 0; @@ -63,25 +64,25 @@ fn scan_line(input: &[u8], output: &mut [u8]) -> Result { cast::usize(run.cnt) }; if x + count > output.len() { - return Err(SubError::Image("scan line is too long".into())); + return Err(VobSubError::Image("scan line is too long".into())); } write_bytes(&mut output[x..x + count], run.val); x += count; } IResult::Err(err) => match err { nom::Err::Incomplete(needed) => { - return Err(SubError::Image(format!( + return Err(VobSubError::Image(format!( "not enough bytes parsing subtitle scan \ line: {needed:?}" ))); } nom::Err::Error(err) => { - return Err(SubError::Image(format!( + return Err(VobSubError::Image(format!( "error parsing subtitle scan line: {err:?}" ))); } nom::Err::Failure(err) => { - return Err(SubError::Image(format!( + return Err(VobSubError::Image(format!( "Failure parsing subtitle scan line: {err:?}" ))); } @@ -89,7 +90,7 @@ fn scan_line(input: &[u8], output: &mut [u8]) -> Result { } } if x > width { - return Err(SubError::Image("decoded scan line is too long".into())); + return Err(VobSubError::Image("decoded scan line is too long".into())); } // Round up to the next full byte. if pos.1 > 0 { @@ -102,7 +103,7 @@ fn scan_line(input: &[u8], output: &mut [u8]) -> Result { /// order, starting at the upper-left and scanning right and down, with one /// byte for each 2-bit value. #[profiling::function] -pub fn decompress(size: Size, data: [&[u8]; 2]) -> Result, SubError> { +pub fn decompress(size: Size, data: [&[u8]; 2]) -> Result, VobSubError> { trace!( "decompressing image {:?}, max: [0x{:x}, 0x{:x}]", &size, diff --git a/src/vobsub/mod.rs b/src/vobsub/mod.rs index 36f9ca1..fb47ea4 100644 --- a/src/vobsub/mod.rs +++ b/src/vobsub/mod.rs @@ -72,45 +72,156 @@ pub use self::palette::{palette, Palette}; pub use self::probe::{is_idx_file, is_sub_file}; pub use self::sub::{subtitles, Subtitle, Subtitles}; -use crate::SubError; -use core::fmt; -use nom::IResult; +use nom::{IResult, Needed}; +use std::{fmt, io, path::PathBuf}; +use thiserror::Error; -/// Extend `IResult` management, and convert to [`Result`] with [`Subrror`] +/// Error for `VobSub` handling. +#[derive(Debug, Error)] +pub enum VobSubError { + /// We were unable to find a required key in an `*.idx` file. + #[error("Could not find required key '{0}'")] + MissingKey(&'static str), + + /// We could not parse a value. + #[error("Could not parse: {0}")] + Parse(String), + + /// If invalid number of palette entries found. + #[error("Palette must have 16 entries, found '{0}' one")] + PaletteInvalidEntriesNumbers(usize), + + /// TODO + #[error("Error during palette pasing from .idx file")] + PaletteError(#[source] NomError), + + /// TODO + #[error("invalid scan line offsets : start 0 {start_0}, start 1 {start_1}, end {end}")] + InvalidScanLineOffsets { + /// Start 0 + start_0: usize, + /// Start 1 + start_1: usize, + /// End + end: usize, + }, + + /// If the buffer is too Small for parsing a 16-bits value. + #[error("unexpected end of buffer while parsing 16-bit size")] + BufferTooSmallForU16, + + /// If the buffer is too small to parse a subtitle. + #[error("unexpected end of subtitle data")] + UnexpectedEndOfSubtitleData, + + /// If an error happen during `Control sequence` parsing. + #[error("Error with Control sequence parsing.")] + ControlSequence(#[source] NomError), + + /// If the control offset value tried to leads backwards. + #[error("control offset value tried to leads backwards")] + ControlOffsetWentBackwards, + + /// If `control offset` is bigger than packet size. + #[error("control offset is 0x{offset:x}, but packet is only 0x{packet:x} bytes")] + ControlOffsetBiggerThanPacket { + /// Control offset + offset: usize, + /// Packet size + packet: usize, + }, + + /// If an error happen during `PES Packet` parsing. + #[error("PES packet parsing.")] + PESPacket(#[source] NomError), + + /// If the `control packet` is incmplete + #[error("Incomplete control packet")] + IncompleteControlPacket, + + /// Packet is too short, not bigger to read his size. + #[error("Packet is too short")] + PacketTooShort, + + /// If timing info for Subtitle is missing. + #[error("found subtitle without timing into")] + MissingTimingForSubtitle, + + /// We could not process a subtitle image. + #[error("Could not process subtitle image: {0}")] + Image(String), + + /// Content Error + #[error("Error with data")] + Content(#[from] crate::content::ContentError), + + /// Io error on a path. + #[error("Io error on '{path}'")] + Io { + /// Source error + source: io::Error, + /// Path of the file we tried to read + path: PathBuf, + }, +} + +/// Error from `nom` handling +#[derive(Debug, Error)] +pub enum NomError { + /// We have leftover input that we didn't expect. + #[error("Unexpected extra input")] + UnexpectedInput, + + /// Our input data ended sooner than we expected. + #[error("Incomplete input: '{0:?}' needed.")] + IncompleteInput(Needed), + + /// An error happend during parsing + #[error("Error from nom : {0}")] + Error(String), + + /// And Failure happend during parsing + #[error("Failure from nom : {0}")] + Failure(String), +} + +/// Extend `IResult` management, and convert to [`Result`] with [`NomError`] pub trait IResultExt { - /// Forward IResult after trailing remaining data. + /// Convert an `IResult` to Result<_, `NomError`> and check than the buffer is empty after parsing. /// # Errors - /// Forward `Error` and `Failure` from nom. - fn ignore_trailing_data(self) -> IResult; - /// Convert an `IResult` to Result<_, `SubError`> + /// Forward `Error` and `Failure` from nom, and return `UnexpectedInput` if the buffer is not empty after parsing. + fn to_result_no_rest(self) -> Result; + + /// Convert an `IResult` to Result<_, `NomError`> /// # Errors - /// return `UnexpectedInput` if there is trailing data after parsing. /// Forward `Error` and `Failure` from nom. - fn to_vobsub_result(self) -> Result; + fn to_result(self) -> Result<(I, O), NomError>; } impl IResultExt for IResult { - fn ignore_trailing_data(self) -> IResult { - match self { - IResult::Ok((_, val)) => IResult::Ok((I::default(), val)), - other => other, - } - } - - fn to_vobsub_result(self) -> Result { + fn to_result_no_rest(self) -> Result { match self { IResult::Ok((rest, val)) => { if rest == I::default() { Ok(val) } else { - Err(SubError::UnexpectedInput) + Err(NomError::UnexpectedInput) } } IResult::Err(err) => match err { - nom::Err::Incomplete(_) => Err(SubError::IncompleteInput), - nom::Err::Error(err) | nom::Err::Failure(err) => { - Err(SubError::Parse(format!("{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 { + IResult::Ok((rest, val)) => Ok((rest, val)), + IResult::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:?}"))), }, } } diff --git a/src/vobsub/mpeg2/ps.rs b/src/vobsub/mpeg2/ps.rs index 1989e75..9a62481 100644 --- a/src/vobsub/mpeg2/ps.rs +++ b/src/vobsub/mpeg2/ps.rs @@ -14,7 +14,7 @@ use nom::{ }; use std::fmt; -use crate::SubError; +use crate::vobsub::{NomError, VobSubError}; use super::clock::{clock_and_ext, Clock}; use super::pes; @@ -111,7 +111,7 @@ pub struct PesPackets<'a> { } impl<'a> Iterator for PesPackets<'a> { - type Item = Result, SubError>; + type Item = Result, VobSubError>; fn next(&mut self) -> Option { loop { @@ -139,7 +139,9 @@ impl<'a> Iterator for PesPackets<'a> { nom::Err::Incomplete(needed) => { self.remaining = &[]; warn!("Incomplete packet, need: {:?}", needed); - return Some(Err(SubError::Parse("Incomplete PES packet".into()))); + return Some(Err(VobSubError::PESPacket(NomError::IncompleteInput( + needed, + )))); } // We got something that looked like a packet but // wasn't parseable. Log it and keep trying. diff --git a/src/vobsub/palette.rs b/src/vobsub/palette.rs index 381253c..471eaf2 100644 --- a/src/vobsub/palette.rs +++ b/src/vobsub/palette.rs @@ -7,7 +7,7 @@ use nom::{ IResult, }; -use crate::SubError; +use super::VobSubError; /// Parse a single hexadecimal digit. fn from_hex(input: &[u8]) -> std::result::Result { @@ -40,7 +40,7 @@ pub type Palette = [Rgb; 16]; pub fn palette(input: &[u8]) -> IResult<&[u8], Palette> { let res = map_res(separated_list0(tag(b", "), hex_rgb), |vec: Vec>| { if vec.len() != 16 { - return Err(SubError::Parse("Palettes must have 16 entries".into())); + return Err(VobSubError::PaletteInvalidEntriesNumbers(vec.len())); } // Coerce vector to known-size slice. Based on // http://stackoverflow.com/q/25428920/12089. diff --git a/src/vobsub/probe.rs b/src/vobsub/probe.rs index 887069e..522b1ec 100644 --- a/src/vobsub/probe.rs +++ b/src/vobsub/probe.rs @@ -1,15 +1,14 @@ //! Try to guess the types of files on disk. +use super::VobSubError; use std::fs; use std::io::Read; use std::path::Path; -use crate::SubError; - /// Internal helper function which looks for "magic" bytes at the start of /// a file. -fn has_magic(path: &Path, magic: &[u8]) -> Result { - let mkerr = |source| SubError::Io { +fn has_magic(path: &Path, magic: &[u8]) -> Result { + let mkerr = |source| VobSubError::Io { source, path: path.into(), }; @@ -24,7 +23,7 @@ fn has_magic(path: &Path, magic: &[u8]) -> Result { /// # Errors /// /// Will return `Err` if the file can't be read. -pub fn is_idx_file>(path: P) -> Result { +pub fn is_idx_file>(path: P) -> Result { has_magic(path.as_ref(), b"# VobSub index file") } @@ -36,7 +35,7 @@ pub fn is_idx_file>(path: P) -> Result { /// # Errors /// /// Will return `Err` if the file can't be read. -pub fn is_sub_file>(path: P) -> Result { +pub fn is_sub_file>(path: P) -> Result { has_magic(path.as_ref(), &[0x00, 0x00, 0x01, 0xba]) } diff --git a/src/vobsub/sub.rs b/src/vobsub/sub.rs index 7e64cd6..462cdb1 100644 --- a/src/vobsub/sub.rs +++ b/src/vobsub/sub.rs @@ -19,13 +19,13 @@ use nom::{ }; use std::{cmp::Ordering, fmt}; -use super::img::decompress; use super::mpeg2::ps; use super::Palette; +use super::{img::decompress, VobSubError}; use crate::{ content::{Area, AreaValues}, util::BytesFormatter, - SubError, + vobsub::IResultExt, }; use image::{ImageBuffer, Rgba, RgbaImage}; @@ -274,24 +274,22 @@ impl fmt::Debug for Subtitle { /// Parse a single `u16` value from a buffer. We don't use `nom` for this /// because it has an inconvenient error type. -fn parse_be_u16_as_usize(buff: &[u8]) -> Result<(&[u8], usize), SubError> { +fn parse_be_u16_as_usize(buff: &[u8]) -> Result<(&[u8], usize), VobSubError> { if buff.len() < 2 { - Err(SubError::Parse( - "unexpected end of buffer while parsing 16-bit size".into(), - )) + Err(VobSubError::BufferTooSmallForU16) } else { Ok((&buff[2..], usize::from(buff[0]) << 8 | usize::from(buff[1]))) } } /// Parse a subtitle. -fn subtitle(raw_data: &[u8], base_time: f64) -> Result { +fn subtitle(raw_data: &[u8], base_time: f64) -> Result { // This parser is somewhat non-standard, because we need to work with // explicit offsets into `packet` in several places. // Figure out where our control data starts. if raw_data.len() < 2 { - return Err(SubError::Parse("unexpected end of subtitle data".into())); + return Err(VobSubError::UnexpectedEndOfSubtitleData); } let (_, initial_control_offset) = parse_be_u16_as_usize(&raw_data[2..])?; @@ -309,91 +307,76 @@ fn subtitle(raw_data: &[u8], base_time: f64) -> Result { loop { trace!("looking for control sequence at: 0x{:x}", control_offset); if control_offset >= raw_data.len() { - return Err(SubError::Parse(format!( - "control offset is 0x{:x}, but packet is only 0x{:x} \ - bytes", - control_offset, - raw_data.len() - ))); + return Err(VobSubError::ControlOffsetBiggerThanPacket { + offset: control_offset, + packet: raw_data.len(), + }); } let control_data = &raw_data[control_offset..]; - match control_sequence(control_data) { - IResult::Ok((_, control)) => { - trace!("parsed control sequence: {:?}", &control); - - // Extract as much data as we can from this control sequence. - let time = base_time + f64::from(control.date) / 100.0; - for command in control.commands { - match command { - ControlCommand::Force => { - force = true; - } - ControlCommand::StartDate => { - start_time = start_time.or(Some(time)); - } - ControlCommand::StopDate => { - end_time = end_time.or(Some(time)); - } - ControlCommand::Palette(p) => { - palette = palette.or(Some(p)); - } - ControlCommand::Alpha(a) => { - alpha = alpha.or(Some(a)); - } - ControlCommand::Coordinates(c) => { - let cmd_area = Area::try_from(c)?; - area = area.or(Some(cmd_area)); - } - ControlCommand::RleOffsets(r) => { - rle_offsets = Some(r); - } - ControlCommand::Unsupported(b) => { - warn!("unsupported control sequence: {:?}", BytesFormatter(b)); - } - } + let (_, control) = control_sequence(control_data) + .to_result() + .map_err(VobSubError::ControlSequence)?; + + trace!("parsed control sequence: {:?}", &control); + + // Extract as much data as we can from this control sequence. + let time = base_time + f64::from(control.date) / 100.0; + for command in control.commands { + match command { + ControlCommand::Force => { + force = true; } - - // Figure out where to look for the next control sequence, - // if any. - let next_control_offset = cast::usize(control.next); - match control_offset.cmp(&next_control_offset) { - Ordering::Greater => { - return Err(SubError::Parse("control offset went backwards".into())); - } - Ordering::Equal => { - // This points back at us, so we're the last packet. - break; - } - Ordering::Less => { - control_offset = next_control_offset; - } + ControlCommand::StartDate => { + start_time = start_time.or(Some(time)); } - } - IResult::Err(err) => match err { - nom::Err::Incomplete(_) => { - return Err(SubError::Parse("incomplete control packet".into())); + ControlCommand::StopDate => { + end_time = end_time.or(Some(time)); + } + ControlCommand::Palette(p) => { + palette = palette.or(Some(p)); + } + ControlCommand::Alpha(a) => { + alpha = alpha.or(Some(a)); + } + ControlCommand::Coordinates(c) => { + let cmd_area = Area::try_from(c)?; + area = area.or(Some(cmd_area)); } - nom::Err::Error(err) => { - return Err(SubError::Parse(format!("error parsing subtitle: {err:?}"))); + ControlCommand::RleOffsets(r) => { + rle_offsets = Some(r); } - nom::Err::Failure(err) => { - return Err(SubError::Parse(format!( - "Failure parsing subtitle: {err:?}" - ))); + ControlCommand::Unsupported(b) => { + warn!("unsupported control sequence: {:?}", BytesFormatter(b)); } - }, + } + } + + // Figure out where to look for the next control sequence, + // if any. + let next_control_offset = cast::usize(control.next); + match control_offset.cmp(&next_control_offset) { + Ordering::Greater => { + return Err(VobSubError::ControlOffsetWentBackwards); + } + Ordering::Equal => { + // This points back at us, so we're the last packet. + break; + } + Ordering::Less => { + control_offset = next_control_offset; + } } } // Make sure we found all the control commands that we expect. let start_time = - start_time.ok_or_else(|| SubError::Parse("no start time for subtitle".into()))?; - let area = area.ok_or_else(|| SubError::Parse("no area coordinates for subtitle".into()))?; - let palette = palette.ok_or_else(|| SubError::Parse("no palette for subtitle".into()))?; - let alpha = alpha.ok_or_else(|| SubError::Parse("no alpha for subtitle".into()))?; + start_time.ok_or_else(|| VobSubError::Parse("no start time for subtitle".into()))?; + let area = area.ok_or_else(|| VobSubError::Parse("no area coordinates for subtitle".into()))?; + let palette = palette.ok_or_else(|| VobSubError::Parse("no palette for subtitle".into()))?; + let alpha = alpha.ok_or_else(|| VobSubError::Parse("no alpha for subtitle".into()))?; let rle_offsets = - rle_offsets.ok_or_else(|| SubError::Parse("no RLE offsets for subtitle".into()))?; + rle_offsets.ok_or_else(|| VobSubError::Parse("no RLE offsets for subtitle".into()))?; // Decompress our image. // @@ -412,7 +395,11 @@ fn subtitle(raw_data: &[u8], base_time: f64) -> Result { let start_1 = cast::usize(rle_offsets[1]); let end = cast::usize(initial_control_offset + 2); if start_0 > start_1 || start_1 > end { - return Err(SubError::Parse("invalid scan line offsets".into())); + return Err(VobSubError::InvalidScanLineOffsets { + start_0, + start_1, + end, + }); } let image = decompress( area.size(), @@ -454,7 +441,7 @@ struct SubtitlesInternal<'a> { } impl<'a> Iterator for SubtitlesInternal<'a> { - type Item = Result; + type Item = Result; fn next(&mut self) -> Option { profiling::scope!("SubtitlesInternal next"); @@ -465,11 +452,7 @@ impl<'a> Iterator for SubtitlesInternal<'a> { // Fetch useful information from our first packet. let pts_dts = match first.pes_packet.header_data.pts_dts { Some(v) => v, - None => { - return Some(Err(SubError::Parse( - "found subtitle without timing into".into(), - ))) - } + None => return Some(Err(VobSubError::MissingTimingForSubtitle)), }; let base_time = pts_dts.pts.as_seconds(); let substream_id = first.pes_packet.substream_id; @@ -477,7 +460,7 @@ impl<'a> Iterator for SubtitlesInternal<'a> { // Figure out how many total bytes we'll need to collect from one // or more PES packets, and collect the first chunk into a buffer. if first.pes_packet.data.len() < 2 { - return Some(Err(SubError::Parse("packet is too short".into()))); + return Some(Err(VobSubError::PacketTooShort)); } let wanted = usize::from(first.pes_packet.data[0]) << 8 | usize::from(first.pes_packet.data[1]); @@ -526,7 +509,7 @@ pub struct Subtitles<'a> { } impl<'a> Iterator for Subtitles<'a> { - type Item = Result; + type Item = Result; // This whole routine exists to make sure that `end_time` is set to a // useful value even if the subtitles themselves didn't supply one.