Skip to content

Commit

Permalink
to_split: big error rework
Browse files Browse the repository at this point in the history
  • Loading branch information
gwen-lg committed May 11, 2024
1 parent a54f3d2 commit b344a86
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 101 deletions.
7 changes: 3 additions & 4 deletions src/content/area.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -53,7 +52,7 @@ impl Area {
}

impl TryFrom<AreaValues> for Area {
type Error = SubError;
type Error = ContentError;

fn try_from(coords_value: AreaValues) -> Result<Self, Self::Error> {
// Check for weird bounding boxes. Ideally we
Expand All @@ -63,7 +62,7 @@ impl TryFrom<AreaValues> 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))
}
Expand Down
10 changes: 10 additions & 0 deletions src/content/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
39 changes: 3 additions & 36 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,13 @@
//! Custom error types.
use std::io;
use std::path::PathBuf;
use thiserror::Error;

use crate::vobsub::NomError;

/// A type representing errors that are specific to `subtile`. Note that we may
/// normally return `Error`, not `SubError`, which allows to return other
/// 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,

/// If an error happen during parsing with `nom`.
#[error("Parsing error.")]
NomParsing(#[from] NomError),

/// 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),
}
24 changes: 13 additions & 11 deletions src/vobsub/idx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -27,9 +25,9 @@ pub struct Index {
impl Index {
/// Open an `*.idx` file and the associated `*.sub` file.
#[profiling::function]
pub fn open<P: AsRef<Path>>(path: P) -> Result<Index, SubError> {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Index, VobSubError> {
let path = path.as_ref();
let mkerr_idx = |source| SubError::Io {
let mkerr_idx = |source| VobSubError::Io {
source,
path: path.into(),
};
Expand All @@ -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(),
})?;
Expand Down Expand Up @@ -77,10 +75,10 @@ impl Index {

/// Read the palette in .idx file content
#[profiling::function]
pub fn read_palette<T, Err>(mut input: BufReader<T>, mkerr: &Err) -> Result<Palette, SubError>
pub fn read_palette<T, Err>(mut input: BufReader<T>, mkerr: &Err) -> Result<Palette, VobSubError>
where
T: std::io::Read,
Err: Fn(io::Error) -> SubError,
Err: Fn(io::Error) -> VobSubError,
{
static KEY_VALUE: Lazy<Regex> = Lazy::new(|| Regex::new("^([A-Za-z/ ]+): (.*)").unwrap());

Expand All @@ -93,15 +91,19 @@ where
let val = cap.get(2).unwrap().as_str();
match key {
"palette" => {
palette_val = Some(palette(val.as_bytes()).to_result_no_rest()?);
palette_val = Some(
palette(val.as_bytes())
.to_result_no_rest()
.map_err(VobSubError::PaletteError)?,
);
}
_ => trace!("Unimplemented idx key: {}", key),
}
}
buf.clear();
}

let palette = palette_val.ok_or(SubError::MissingKey("palette"))?;
let palette = palette_val.ok_or(VobSubError::MissingKey("palette"))?;
Ok(palette)
}

Expand Down
17 changes: 9 additions & 8 deletions src/vobsub/img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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<usize, SubError> {
fn scan_line(input: &[u8], output: &mut [u8]) -> Result<usize, VobSubError> {
trace!("scan line starting with {:?}", BytesFormatter(input));
let width = output.len();
let mut x = 0;
Expand All @@ -63,33 +64,33 @@ fn scan_line(input: &[u8], output: &mut [u8]) -> Result<usize, SubError> {
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:?}"
)));
}
},
}
}
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 {
Expand All @@ -102,7 +103,7 @@ fn scan_line(input: &[u8], output: &mut [u8]) -> Result<usize, SubError> {
/// 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<Vec<u8>, SubError> {
pub fn decompress(size: Size, data: [&[u8]; 2]) -> Result<Vec<u8>, VobSubError> {
trace!(
"decompressing image {:?}, max: [0x{:x}, 0x{:x}]",
&size,
Expand Down
91 changes: 90 additions & 1 deletion src/vobsub/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,98 @@ pub use self::probe::{is_idx_file, is_sub_file};
pub use self::sub::{subtitles, Subtitle, Subtitles};

use nom::{IResult, Needed};
use std::fmt;
use std::{fmt, io, path::PathBuf};
use thiserror::Error;

/// 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 {
Expand Down
8 changes: 5 additions & 3 deletions src/vobsub/mpeg2/ps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -111,7 +111,7 @@ pub struct PesPackets<'a> {
}

impl<'a> Iterator for PesPackets<'a> {
type Item = Result<PesPacket<'a>, SubError>;
type Item = Result<PesPacket<'a>, VobSubError>;

fn next(&mut self) -> Option<Self::Item> {
loop {
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions src/vobsub/palette.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8, std::num::ParseIntError> {
Expand Down Expand Up @@ -40,7 +40,7 @@ pub type Palette = [Rgb<u8>; 16];
pub fn palette(input: &[u8]) -> IResult<&[u8], Palette> {
let res = map_res(separated_list0(tag(b", "), hex_rgb), |vec: Vec<Rgb<u8>>| {
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.
Expand Down
Loading

0 comments on commit b344a86

Please sign in to comment.