From 04d1a669d1ccd7d018bab512b73cf4c9a81453a6 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Sun, 2 Apr 2023 10:54:12 +0200 Subject: [PATCH 1/6] Reimplement value parsing for sized EBML types * Introduce `EbmlParsable` trait to parse most known EBML types * Rename `ErrorKind` to `ParseError` * Move Element ID from `ParseError` into the `Error` enum --- src/demuxer.rs | 16 ++-- src/ebml.rs | 248 ++++++++++++++++++++----------------------------- 2 files changed, 109 insertions(+), 155 deletions(-) diff --git a/src/demuxer.rs b/src/demuxer.rs index f8007b7..e744129 100644 --- a/src/demuxer.rs +++ b/src/demuxer.rs @@ -15,7 +15,7 @@ use av_format::{ }; use crate::{ - ebml::{self, ebml_err, ebml_header, EbmlHeader, ErrorKind}, + ebml::{self, ebml_err, ebml_header, EbmlHeader, ParseError}, elements::{ segment, segment_element, simple_block, Audio, Cluster, Info, SeekHead, SegmentElement, TrackEntry, TrackType, Tracks, Video, @@ -81,23 +81,23 @@ impl MkvDemuxer { match element { SegmentElement::SeekHead(s) => { - trace!("got seek head: {:#?}", s); + trace!("got seek head: {s:#?}"); self.seek_head = if self.seek_head.is_none() { Some(s) } else { - return ebml_err(ErrorKind::DuplicateSegment(0x114D9B74)); + return ebml_err(0x114D9B74, ParseError::DuplicateSegment); }; } SegmentElement::Info(i) => { - trace!("got info: {:#?}", i); + trace!("got info: {i:#?}"); self.info = if self.info.is_none() { Some(i) } else { - return ebml_err(ErrorKind::DuplicateSegment(0x1549A966)); + return ebml_err(0x1549A966, ParseError::DuplicateSegment); }; } SegmentElement::Tracks(t) => { - trace!("got tracks: {:#?}", t); + trace!("got tracks: {t:#?}"); self.tracks = if self.tracks.is_none() { let mut t = t; @@ -111,11 +111,11 @@ impl MkvDemuxer { Some(t) } else { - return ebml_err(ErrorKind::DuplicateSegment(0x1654AE6B)); + return ebml_err(0x1654AE6B, ParseError::DuplicateSegment); } } el => { - debug!("got element: {:#?}", el); + debug!("got element: {el:#?}"); } } diff --git a/src/ebml.rs b/src/ebml.rs index 246df20..fb830bd 100644 --- a/src/ebml.rs +++ b/src/ebml.rs @@ -1,11 +1,13 @@ -use std::convert::TryFrom; +use std::{ + convert::TryFrom, + ops::{BitOr, Shl}, +}; use crc::{Algorithm, Crc}; use log::trace; use nom::{ bytes::streaming::take, - combinator::{complete, flat_map, map, map_parser, map_res, opt, verify}, - number::streaming::{be_f32, be_f64}, + combinator::{complete, map, map_parser, map_res, opt, verify}, sequence::{pair, preceded, tuple}, Err, Needed, Parser, }; @@ -20,31 +22,30 @@ pub enum Error { Nom(nom::error::ErrorKind), /// nom did not return an error, but the EBML is incorrect. - Ebml(ErrorKind), -} - -// TODO: Add Element IDs (u64) to more of these variants - -/// The [u64] contained in some of these error variants represents the -/// EBML or Matroska Element ID of the element where the error occurred. -/// -/// For an overview of all Element IDs, see: -/// -/// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebml-element-ids-registry -/// -/// https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-15.html#section-27.1-11 + /// The contained [u32] is the Element ID of the Element where the + /// error occurred, or 0 if not applicable. + /// + /// For an overview of Element IDs, see the list of + /// [EBML Element IDs] or [Matroska Element IDs]. + /// + /// [EBML Element IDs]: https://www.rfc-editor.org/rfc/rfc8794.html#name-ebml-element-ids-registry + /// [Matroska Element IDs]: https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-15.html#section-27.1-11 + Ebml(u32, ParseError), +} + +/// Describes what went wrong. #[derive(Debug, PartialEq, Eq)] #[non_exhaustive] -pub enum ErrorKind { +pub enum ParseError { /// The Element Data Size did not fit within a [usize]. /// The current parsing code cannot handle an element of this size. ElementTooLarge, /// A required value was not found by the parser. - MissingRequiredValue(u32), + MissingRequiredValue, /// One of the segment element types was discovered more than once in the input. - DuplicateSegment(u64), + DuplicateSegment, /// The VINT_WIDTH is 8 or more, which means that the resulting variable-size /// integer is more than 8 octets wide. This is currently not supported. @@ -57,26 +58,26 @@ pub enum ErrorKind { /// A signed integer element has declared a length of more than 8 octets, /// which is not allowed. - IntTooWide(u32), + IntTooWide, /// An unsigned integer with a maximum length of 4 octets has declared a /// length of more than 4 octets, which is not allowed. - U32TooWide(u32), + U32TooWide, /// An unsigned integer element has declared a length of more than 8 octets, /// which is not allowed. - UintTooWide(u32), + UintTooWide, /// A float element has declared a length that is not 0, 4 or 8 octets, /// which is not allowed. - FloatWidthIncorrect(u32), + FloatWidthIncorrect, /// A string element contains non-UTF-8 data, which is not allowed. - StringNotUtf8(u32), + StringNotUtf8, /// A binary element does not adhere to the length declared in the - /// specification. - BinaryWidthIncorrect(usize, u32), + /// specification. The enclosed [u16] is the actual length of the data. + BinaryWidthIncorrect(u16), /// A CRC-32 element was found, but the checksum did not match. Crc32Mismatch, @@ -92,20 +93,20 @@ impl<'a> nom::error::ParseError<&'a [u8]> for Error { } } -pub fn ebml_err<'a, T>(err: ErrorKind) -> EbmlResult<'a, T> { - Err(nom::Err::Error(Error::Ebml(err))) -} - impl nom::error::FromExternalError for Error { fn from_external_error(_input: I, _kind: nom::error::ErrorKind, e: Error) -> Self { e } } +pub fn ebml_err<'a, T>(id: u32, err: ParseError) -> EbmlResult<'a, T> { + Err(nom::Err::Error(Error::Ebml(id, err))) +} + pub(crate) fn value_error(id: u32, value: Option) -> Result> { value.ok_or_else(|| { log::error!("Not possible to get the requested value"); - nom::Err::Error(Error::Ebml(ErrorKind::MissingRequiredValue(id))) + nom::Err::Error(Error::Ebml(id, ParseError::MissingRequiredValue)) }) } @@ -118,7 +119,7 @@ pub fn vint(input: &[u8]) -> EbmlResult { let len = v.leading_zeros(); if len == 8 { - return ebml_err(ErrorKind::VintTooWide); + return ebml_err(0, ParseError::VintTooWide); } if input.len() <= len as usize { @@ -150,7 +151,7 @@ pub fn elem_size(input: &[u8]) -> EbmlResult { map_res(vint, |u| { usize::try_from(u).map_err(|_| { log::error!("Element Data Size does not fit into usize"); - Error::Ebml(ErrorKind::ElementTooLarge) + Error::Ebml(0, ParseError::ElementTooLarge) }) })(input) } @@ -162,167 +163,120 @@ pub fn vid(input: &[u8]) -> EbmlResult { return Err(Err::Incomplete(Needed::new(1))); } - let v = input[0]; - let len = v.leading_zeros(); - - if len == 8 { - return ebml_err(ErrorKind::IDTooWide); - } + let len = 1 + input[0].leading_zeros() as usize; - if input.len() <= len as usize { + if input.len() <= len { return Err(Err::Incomplete(Needed::new(1))); } - let mut val = u32::from(v); - - trace!("vid {val:08b} {v:08b} {:08b} {len}", (1 << (8 - len))); - - for i in 0..len as usize { - val = (val << 8) | u32::from(input[i + 1]); + match u32::try_parse(&input[..len]) { + Ok(id) => Ok((&input[len..], id)), + Err(_) => ebml_err(0, ParseError::IDTooWide), } - - trace!(" result {:08x}", val); - - Ok((&input[len as usize + 1..], val)) } -pub fn parse_u32_data(id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult { - move |input| { - let mut val = 0; - - if size > 4 { - return ebml_err(ErrorKind::U32TooWide(id)); - } - - for i in input.iter().take(size) { - val = (val << 8) | u32::from(*i); - } - - Ok((&input[size..], val)) - } +trait EbmlParsable: Sized { + fn try_parse(data: &[u8]) -> Result; } -pub fn parse_uint_data(id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult { - move |input| { - let mut val = 0; +// Parsable implementation for the integer types +trait Int: From + Shl + BitOr {} +impl Int for u64 {} +impl Int for u32 {} +impl Int for i64 {} - if size > 8 { - return ebml_err(ErrorKind::UintTooWide(id)); +impl EbmlParsable for T { + fn try_parse(data: &[u8]) -> Result { + if data.len() > std::mem::size_of::() { + return Err(ParseError::IntTooWide); } - for i in input.iter().take(size) { - val = (val << 8) | u64::from(*i); + let mut val = Self::from(0); + for b in data { + val = (val << Self::from(8)) | Self::from(*b); } - Ok((&input[size..], val)) + Ok(val) } } -pub fn parse_int_data(id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult { - move |input| { - let mut val = 0; - - if size > 8 { - return ebml_err(ErrorKind::IntTooWide(id)); - } - - for i in input.iter().take(size) { - val = (val << 8) | u64::from(*i); +//FIXME: handle default values +//FIXME: is that really following IEEE_754-1985 ? +impl EbmlParsable for f64 { + fn try_parse(data: &[u8]) -> Result { + match data.len() { + 0 => Ok(0.0), + 4 => Ok(f64::from(f32::from_be_bytes(data.try_into().unwrap()))), + 8 => Ok(f64::from_be_bytes(data.try_into().unwrap())), + _ => Err(ParseError::FloatWidthIncorrect), } - - Ok((&input[size..], val as i64)) } } -pub fn parse_str_data(id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult { - move |input| { - take(size)(input).and_then(|(i, data)| match String::from_utf8(data.to_owned()) { - Ok(s) => Ok((i, s)), - Err(_) => ebml_err(ErrorKind::StringNotUtf8(id)), - }) +impl EbmlParsable for String { + fn try_parse(data: &[u8]) -> Result { + String::from_utf8(data.to_vec()).map_err(|_| ParseError::StringNotUtf8) } } -pub fn parse_binary_exact( - _id: u32, - size: usize, -) -> impl Fn(&[u8]) -> EbmlResult<[u8; N]> { - move |input| match map(take(size), <[u8; N]>::try_from)(input) { - Ok((i, Ok(arr))) => Ok((i, arr)), - Ok((_, Err(_))) => ebml_err(ErrorKind::BinaryWidthIncorrect(size, N as u32)), - Err(e) => Err(e), +impl EbmlParsable for [u8; N] { + fn try_parse(data: &[u8]) -> Result { + let actual_len = data.len(); + data.try_into() + .map_err(|_| ParseError::BinaryWidthIncorrect(actual_len as u16)) } } -pub fn parse_binary_data(_id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult> { - move |input| map(take(size), |data: &[u8]| data.to_owned())(input) -} - -pub fn parse_binary_data_ref(_id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult<&[u8]> { - move |input| map(take(size), |data| data)(input) -} - -//FIXME: handle default values -//FIXME: is that really following IEEE_754-1985 ? -pub fn parse_float_data(id: u32, size: usize) -> impl Fn(&[u8]) -> EbmlResult { - move |input| { - if size == 0 { - Ok((input, 0f64)) - } else if size == 4 { - map(map_parser(take(size), be_f32), f64::from)(input) - } else if size == 8 { - map_parser(take(size), be_f64)(input) - } else { - ebml_err(ErrorKind::FloatWidthIncorrect(id)) - } +impl EbmlParsable for Vec { + fn try_parse(data: &[u8]) -> Result { + Ok(data.to_vec()) } } -fn compute_ebml_type<'a, G, H, O1>(id: u32, second: G) -> impl Fn(&'a [u8]) -> EbmlResult<'a, O1> -where - G: Fn(u32, usize) -> H, - H: Parser<&'a [u8], O1, Error>, -{ +fn compute_ebml_type(id: u32) -> impl Fn(&[u8]) -> EbmlResult { move |i| { - flat_map( - pair(verify(vid, |val| *val == id), elem_size), - |(id, size)| second(id, size), - )(i) + let (i, (_, size)) = pair(verify(vid, |val| *val == id), elem_size)(i)?; + map_res(take(size), |d| { + O::try_parse(d).map_err(|k| Error::Ebml(id, k)) + })(i) } } -pub fn ebml_u32<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, u32> { - compute_ebml_type(id, parse_u32_data) +pub fn ebml_u32(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + compute_ebml_type(id) } -pub fn ebml_uint<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, u64> { - compute_ebml_type(id, parse_uint_data) +pub fn ebml_uint(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + compute_ebml_type(id) } -pub fn ebml_int<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, i64> { - compute_ebml_type(id, parse_int_data) +pub fn ebml_int(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + compute_ebml_type(id) } -pub fn ebml_float<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, f64> { - compute_ebml_type(id, parse_float_data) +pub fn ebml_float(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + compute_ebml_type(id) } -pub fn ebml_str<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, String> { - compute_ebml_type(id, parse_str_data) +pub fn ebml_str(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + compute_ebml_type(id) } -pub fn ebml_binary_exact<'a, const N: usize>( - id: u32, -) -> impl Fn(&'a [u8]) -> EbmlResult<'a, [u8; N]> { - compute_ebml_type(id, parse_binary_exact) +pub fn ebml_binary_exact(id: u32) -> impl Fn(&[u8]) -> EbmlResult<[u8; N]> { + compute_ebml_type(id) } -pub fn ebml_binary<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, Vec> { - compute_ebml_type(id, parse_binary_data) +pub fn ebml_binary(id: u32) -> impl Fn(&[u8]) -> EbmlResult> { + compute_ebml_type(id) } -pub fn ebml_binary_ref<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<'a, &'a [u8]> { - compute_ebml_type(id, parse_binary_data_ref) +// Doing this via EbmlParsable would make the trait more +// complicated, so it gets special treatment instead. +pub fn ebml_binary_ref<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<&'a [u8]> { + move |i| { + let (i, (_, size)) = pair(verify(vid, |val| *val == id), elem_size)(i)?; + take(size)(i) + } } pub fn ebml_master<'a, G, O1>(id: u32, second: G) -> impl Fn(&'a [u8]) -> EbmlResult<'a, O1> @@ -366,7 +320,7 @@ where // FIXME: don't just return an error, the spec has well-defined CRC error handling match crc { - Some(cs) if cs != CRC.checksum(o) => ebml_err(ErrorKind::Crc32Mismatch), + Some(cs) if cs != CRC.checksum(o) => ebml_err(0, ParseError::Crc32Mismatch), _ => Ok((i, o)), } } From 176305a78ca4cd9e91890b43d9b3c98cdc78fc8a Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Sun, 2 Apr 2023 15:30:19 +0200 Subject: [PATCH 2/6] Refactoring based on previous commit * Remove `ebml_` prefix from parsing functions * Move `complete` combinator into parsing functions * Implement EbmlParsable for Uuid * Rename `skip_void` to `void` (The combinator doesn't really skip the void, it returns it) * Rename `eat_void` to `skip_void` (better description) --- src/ebml.rs | 106 +++++++----- src/elements.rs | 378 ++++++++++++++++++++--------------------- src/permutation.rs | 3 +- src/serializer/ebml.rs | 4 +- 4 files changed, 249 insertions(+), 242 deletions(-) diff --git a/src/ebml.rs b/src/ebml.rs index fb830bd..00b271b 100644 --- a/src/ebml.rs +++ b/src/ebml.rs @@ -7,10 +7,11 @@ use crc::{Algorithm, Crc}; use log::trace; use nom::{ bytes::streaming::take, - combinator::{complete, map, map_parser, map_res, opt, verify}, - sequence::{pair, preceded, tuple}, + combinator::{complete, flat_map, map, map_parser, map_res, opt, verify}, + sequence::{preceded, tuple}, Err, Needed, Parser, }; +use uuid::Uuid; use crate::permutation::matroska_permutation; @@ -233,55 +234,67 @@ impl EbmlParsable for Vec { } } -fn compute_ebml_type(id: u32) -> impl Fn(&[u8]) -> EbmlResult { +impl EbmlParsable for Uuid { + fn try_parse(data: &[u8]) -> Result { + <[u8; 16] as EbmlParsable>::try_parse(data).map(Uuid::from_bytes) + } +} + +fn ebml_generic(id: u32) -> impl Fn(&[u8]) -> EbmlResult { move |i| { - let (i, (_, size)) = pair(verify(vid, |val| *val == id), elem_size)(i)?; - map_res(take(size), |d| { - O::try_parse(d).map_err(|k| Error::Ebml(id, k)) - })(i) + let data = flat_map(preceded(verify(vid, |val| *val == id), elem_size), take); + let parsed = map_res(data, |d| O::try_parse(d).map_err(|k| Error::Ebml(id, k))); + complete(parsed)(i) } } -pub fn ebml_u32(id: u32) -> impl Fn(&[u8]) -> EbmlResult { - compute_ebml_type(id) +pub fn u32(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + ebml_generic(id) } -pub fn ebml_uint(id: u32) -> impl Fn(&[u8]) -> EbmlResult { - compute_ebml_type(id) +pub fn uint(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + ebml_generic(id) } -pub fn ebml_int(id: u32) -> impl Fn(&[u8]) -> EbmlResult { - compute_ebml_type(id) +pub fn int(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + ebml_generic(id) } -pub fn ebml_float(id: u32) -> impl Fn(&[u8]) -> EbmlResult { - compute_ebml_type(id) +pub fn float(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + ebml_generic(id) } -pub fn ebml_str(id: u32) -> impl Fn(&[u8]) -> EbmlResult { - compute_ebml_type(id) +pub fn str(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + ebml_generic(id) } -pub fn ebml_binary_exact(id: u32) -> impl Fn(&[u8]) -> EbmlResult<[u8; N]> { - compute_ebml_type(id) +pub fn binary_exact(id: u32) -> impl Fn(&[u8]) -> EbmlResult<[u8; N]> { + ebml_generic(id) } -pub fn ebml_binary(id: u32) -> impl Fn(&[u8]) -> EbmlResult> { - compute_ebml_type(id) +pub fn binary(id: u32) -> impl Fn(&[u8]) -> EbmlResult> { + ebml_generic(id) } -// Doing this via EbmlParsable would make the trait more -// complicated, so it gets special treatment instead. -pub fn ebml_binary_ref<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<&'a [u8]> { +pub fn uuid(id: u32) -> impl Fn(&[u8]) -> EbmlResult { + ebml_generic(id) +} + +// Doing this via EbmlParsable would make the trait more complicated, +// so it gets special treatment instead. This basically does the same +// thing as ebml_generic(id), but without a mapping function. +pub fn binary_ref<'a>(id: u32) -> impl Fn(&'a [u8]) -> EbmlResult<&'a [u8]> { move |i| { - let (i, (_, size)) = pair(verify(vid, |val| *val == id), elem_size)(i)?; - take(size)(i) + complete(flat_map( + preceded(verify(vid, |val| *val == id), elem_size), + take, + ))(i) } } -pub fn ebml_master<'a, G, O1>(id: u32, second: G) -> impl Fn(&'a [u8]) -> EbmlResult<'a, O1> +pub fn master<'a, F, O>(id: u32, second: F) -> impl Fn(&'a [u8]) -> EbmlResult<'a, O> where - G: Fn(&'a [u8]) -> EbmlResult<'a, O1> + Copy, + F: Parser<&'a [u8], O, Error> + Copy, { move |i| { tuple((verify(vid, |val| *val == id), elem_size, crc))(i).and_then(|(i, (_, size, crc))| { @@ -291,15 +304,15 @@ where } } -pub fn eat_void<'a, G, O1>(second: G) -> impl Fn(&'a [u8]) -> EbmlResult<'a, O1> +pub fn skip_void<'a, F, O>(second: F) -> impl FnMut(&'a [u8]) -> EbmlResult<'a, O> where - G: Parser<&'a [u8], O1, Error> + Copy, + F: Parser<&'a [u8], O, Error> + Copy, { - move |i| preceded(opt(skip_void), second)(i) + preceded(opt(void), second) } -pub fn skip_void(input: &[u8]) -> EbmlResult<&[u8]> { - pair(verify(vid, |val| *val == 0xEC), elem_size)(input).and_then(|(i, (_, size))| take(size)(i)) +pub fn void(input: &[u8]) -> EbmlResult<&[u8]> { + binary_ref(0xEC)(input) } const CRC: Crc = Crc::::new(&Algorithm { @@ -308,15 +321,18 @@ const CRC: Crc = Crc::::new(&Algorithm { }); pub fn crc(input: &[u8]) -> EbmlResult> { - opt(map(ebml_binary_exact::<4>(0xBF), u32::from_le_bytes))(input) + opt(map(binary_exact::<4>(0xBF), u32::from_le_bytes))(input) } -pub fn checksum<'a, G>(crc: Option, inner: G) -> impl Fn(&'a [u8]) -> EbmlResult<'a, &'a [u8]> +pub fn checksum<'a, F>( + crc: Option, + mut inner: F, +) -> impl FnMut(&'a [u8]) -> EbmlResult<'a, &'a [u8]> where - G: Fn(&'a [u8]) -> EbmlResult<'a, &'a [u8]>, + F: Parser<&'a [u8], &'a [u8], Error>, { move |input| { - let (i, o) = inner(input)?; + let (i, o) = inner.parse(input)?; // FIXME: don't just return an error, the spec has well-defined CRC error handling match crc { @@ -338,15 +354,15 @@ pub struct EbmlHeader { } pub fn ebml_header(input: &[u8]) -> EbmlResult { - ebml_master(0x1A45DFA3, |i| { + master(0x1A45DFA3, |i| { matroska_permutation(( - complete(ebml_u32(0x4286)), // version - complete(ebml_u32(0x42F7)), // read_version - complete(ebml_u32(0x42F2)), // max id length - complete(ebml_u32(0x42F3)), // max size length - complete(ebml_str(0x4282)), // doctype - complete(ebml_u32(0x4287)), // doctype version - complete(ebml_u32(0x4285)), // doctype_read version + u32(0x4286), // version + u32(0x42F7), // read_version + u32(0x42F2), // max id length + u32(0x42F3), // max size length + str(0x4282), // doctype + u32(0x4287), // doctype version + u32(0x4285), // doctype_read version ))(i) .and_then(|(i, t)| { Ok(( diff --git a/src/elements.rs b/src/elements.rs index 3f3070d..0794c4b 100644 --- a/src/elements.rs +++ b/src/elements.rs @@ -9,8 +9,8 @@ use nom::{ pub use uuid::Uuid; use crate::ebml::{ - checksum, crc, eat_void, ebml_binary, ebml_binary_exact, ebml_binary_ref, ebml_float, ebml_int, - ebml_master, ebml_str, ebml_uint, elem_size, value_error, vid, vint, EbmlResult, + binary, binary_ref, checksum, crc, skip_void, elem_size, float, int, master, str, uint, uuid, + value_error, vid, vint, EbmlResult, }; use crate::permutation::matroska_permutation; @@ -87,10 +87,10 @@ pub struct Seek { //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.4 pub fn seek(input: &[u8]) -> EbmlResult { - ebml_master(0x4DBB, |inp| { + master(0x4DBB, |inp| { matroska_permutation(( - complete(ebml_binary(0x53AB)), // SeekID - complete(ebml_uint(0x53AC)), // SeekPosition + binary(0x53AB), // SeekID + uint(0x53AC), // SeekPosition ))(inp) .and_then(|(i, t)| { Ok(( @@ -125,32 +125,32 @@ pub struct Info { //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.8 pub fn info(input: &[u8]) -> EbmlResult { matroska_permutation(( - complete(ebml_binary_exact::<16>(0x73A4)), // SegmentUID - complete(ebml_str(0x7384)), // SegmentFIlename FIXME SHOULD BE UTF-8 not str - complete(ebml_binary_exact::<16>(0x3CB923)), // PrevUID - complete(ebml_str(0x3C83AB)), // PrevFilename FIXME SHOULD BE UTF-8 not str - complete(ebml_binary_exact::<16>(0x3EB923)), // NextUID - complete(ebml_str(0x3E83BB)), // NextFilename FIXME SHOULD BE UTF-8 not str - complete(ebml_binary_exact::<16>(0x4444)), // SegmentFamily + uuid(0x73A4), // SegmentUID + str(0x7384), // SegmentFIlename FIXME SHOULD BE UTF-8 not str + uuid(0x3CB923), // PrevUID + str(0x3C83AB), // PrevFilename FIXME SHOULD BE UTF-8 not str + uuid(0x3EB923), // NextUID + str(0x3E83BB), // NextFilename FIXME SHOULD BE UTF-8 not str + uuid(0x4444), // SegmentFamily complete(chapter_translate), // - complete(ebml_uint(0x2AD7B1)), // TimecodeScale - complete(ebml_float(0x4489)), // Duration: FIXME should be float - complete(ebml_binary(0x4461)), // DateUTC FIXME: should be date - complete(ebml_str(0x7BA9)), // Title FIXME SHOULD BE UTF-8 not str - complete(ebml_str(0x4D80)), // MuxingApp FIXME SHOULD BE UTF-8 not str - complete(ebml_str(0x5741)), // WritingApp FIXME SHOULD BE UTF-8 not str + uint(0x2AD7B1), // TimecodeScale + float(0x4489), // Duration: FIXME should be float + binary(0x4461), // DateUTC FIXME: should be date + str(0x7BA9), // Title FIXME SHOULD BE UTF-8 not str + str(0x4D80), // MuxingApp FIXME SHOULD BE UTF-8 not str + str(0x5741), // WritingApp FIXME SHOULD BE UTF-8 not str ))(input) .and_then(|(i, t)| { Ok(( i, SegmentElement::Info(Info { - segment_uid: t.0.map(Uuid::from_bytes), + segment_uid: t.0, segment_filename: t.1, - prev_uid: t.2.map(Uuid::from_bytes), + prev_uid: t.2, prev_filename: t.3, - next_uid: t.4.map(Uuid::from_bytes), + next_uid: t.4, next_filename: t.5, - segment_family: t.6.map(Uuid::from_bytes), + segment_family: t.6, chapter_translate: t.7, timecode_scale: value_error(0x2AD7B1, t.8)?, duration: t.9, @@ -168,7 +168,7 @@ pub struct ChapterTranslate {} //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.16 pub fn chapter_translate(input: &[u8]) -> EbmlResult { - ebml_master(0x6924, |i| Ok((i, ChapterTranslate {})))(input) + master(0x6924, |i| Ok((i, ChapterTranslate {})))(input) } //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.26 @@ -185,13 +185,13 @@ pub struct Cluster<'a> { pub fn cluster(input: &[u8]) -> EbmlResult { matroska_permutation(( - complete(ebml_uint(0xE7)), + uint(0xE7), complete(silent_tracks), - complete(ebml_uint(0xA7)), - complete(ebml_uint(0xAB)), - many0(complete(ebml_binary_ref(0xA3))), + uint(0xA7), + uint(0xAB), + many0(binary_ref(0xA3)), many0(complete(block_group)), - complete(ebml_binary_ref(0xAF)), + binary_ref(0xAF), ))(input) .and_then(|(i, t)| { Ok(( @@ -216,8 +216,8 @@ pub struct SilentTracks { //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.16 pub fn silent_tracks(input: &[u8]) -> EbmlResult { - ebml_master(0x5854, |i| { - map(many0(ebml_uint(0x58D7)), |v| SilentTracks { numbers: v })(i) + master(0x5854, |i| { + map(many0(uint(0x58D7)), |v| SilentTracks { numbers: v })(i) })(input) } @@ -238,17 +238,17 @@ pub struct BlockGroup<'a> { //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.16 pub fn block_group(input: &[u8]) -> EbmlResult { - ebml_master(0xA0, |inp| { + master(0xA0, |inp| { matroska_permutation(( - complete(ebml_binary_ref(0xA1)), - complete(ebml_binary(0xA2)), + binary_ref(0xA1), + binary(0xA2), complete(block_additions), - complete(ebml_uint(0x9B)), - complete(ebml_uint(0xFA)), - complete(ebml_uint(0xFB)), - complete(ebml_int(0xFD)), - complete(ebml_binary(0xA4)), - complete(ebml_int(0x75A2)), + uint(0x9B), + uint(0xFA), + uint(0xFB), + int(0xFD), + binary(0xA4), + int(0x75A2), complete(slices), complete(reference_frame), ))(inp) @@ -278,7 +278,7 @@ pub struct BlockAdditions {} //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.16 pub fn block_additions(input: &[u8]) -> EbmlResult { - ebml_master(0x75A1, |i| Ok((i, BlockAdditions {})))(input) + master(0x75A1, |i| Ok((i, BlockAdditions {})))(input) } #[derive(Debug, Clone, PartialEq, Eq)] @@ -286,7 +286,7 @@ pub struct Slices {} //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.46 pub fn slices(input: &[u8]) -> EbmlResult { - ebml_master(0x8E, |i| Ok((i, Slices {})))(input) + master(0x8E, |i| Ok((i, Slices {})))(input) } #[derive(Debug, Clone, PartialEq, Eq)] @@ -294,7 +294,7 @@ pub struct ReferenceFrame {} //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.53 pub fn reference_frame(input: &[u8]) -> EbmlResult { - ebml_master(0xC8, |i| Ok((i, ReferenceFrame {})))(input) + master(0xC8, |i| Ok((i, ReferenceFrame {})))(input) } #[derive(Debug, Clone, PartialEq, Eq)] @@ -404,7 +404,7 @@ impl Tracks { //https://datatracker.ietf.org/doc/html/draft-lhomme-cellar-matroska-03#section-7.3.16 pub fn tracks(input: &[u8]) -> EbmlResult { - map(many1(complete(eat_void(track_entry))), |v| { + map(many1(complete(skip_void(track_entry))), |v| { SegmentElement::Tracks(Tracks { tracks: v }) })(input) } @@ -480,45 +480,45 @@ pub struct TrackEntry { } pub fn track_entry(input: &[u8]) -> EbmlResult { - ebml_master(0xAE, |inp| { + master(0xAE, |inp| { matroska_permutation(( - complete(ebml_uint(0xD7)), - complete(ebml_uint(0x73C5)), - complete(ebml_uint(0x83)), - complete(ebml_uint(0xB9)), - complete(ebml_uint(0x88)), - complete(ebml_uint(0x55AA)), - complete(ebml_uint(0x9C)), - complete(ebml_uint(0x6DE7)), - complete(ebml_uint(0x6DF8)), - complete(ebml_uint(0x23E383)), - complete(ebml_uint(0x234E7A)), - complete(ebml_float(0x23314F)), - complete(ebml_int(0x537F)), - complete(ebml_uint(0x55EE)), - complete(ebml_str(0x536E)), - complete(ebml_str(0x22B59C)), - complete(ebml_str(0x22B59D)), - complete(ebml_str(0x86)), - complete(ebml_binary(0x63A2)), - complete(ebml_str(0x258688)), - complete(ebml_uint(0x7446)), - complete(ebml_str(0x3A9697)), - complete(ebml_str(0x3B4040)), - complete(ebml_str(0x26B240)), - complete(ebml_uint(0xAA)), - complete(ebml_uint(0x6FAB)), - complete(ebml_uint(0x56AA)), - complete(ebml_uint(0x56BB)), + uint(0xD7), + uint(0x73C5), + uint(0x83), + uint(0xB9), + uint(0x88), + uint(0x55AA), + uint(0x9C), + uint(0x6DE7), + uint(0x6DF8), + uint(0x23E383), + uint(0x234E7A), + float(0x23314F), + int(0x537F), + uint(0x55EE), + str(0x536E), + str(0x22B59C), + str(0x22B59D), + str(0x86), + binary(0x63A2), + str(0x258688), + uint(0x7446), + str(0x3A9697), + str(0x3B4040), + str(0x26B240), + uint(0xAA), + uint(0x6FAB), + uint(0x56AA), + uint(0x56BB), many0(complete(track_translate)), complete(video), complete(audio), complete(track_operation), - complete(ebml_uint(0xC0)), - complete(ebml_binary_exact::<16>(0xC1)), - complete(ebml_uint(0xC6)), - complete(ebml_uint(0xC7)), - complete(ebml_binary_exact::<16>(0xC4)), + uint(0xC0), + uuid(0xC1), + uint(0xC6), + uint(0xC7), + uuid(0xC4), complete(content_encodings), ))(inp) .and_then(|(i, t)| { @@ -558,10 +558,10 @@ pub fn track_entry(input: &[u8]) -> EbmlResult { audio: t.30, track_operation: t.31, trick_track_uid: t.32, - trick_track_segment_uid: t.33.map(Uuid::from_bytes), + trick_track_segment_uid: t.33, trick_track_flag: t.34, trick_master_track_uid: t.35, - trick_master_track_segment_uid: t.36.map(Uuid::from_bytes), + trick_master_track_segment_uid: t.36, content_encodings: t.37, stream_index: 0, }, @@ -578,22 +578,19 @@ pub struct TrackTranslate { } pub fn track_translate(input: &[u8]) -> EbmlResult { - ebml_master(0x6624, |inp| { - matroska_permutation(( - many1(complete(ebml_uint(0x66FC))), - complete(ebml_uint(0x66BF)), - complete(ebml_uint(0x66A5)), - ))(inp) - .and_then(|(i, t)| { - Ok(( - i, - TrackTranslate { - edition_uid: value_error(0x66FC, t.0)?, - codec: value_error(0x66BF, t.1)?, - track_id: value_error(0x66A5, t.2)?, - }, - )) - }) + master(0x6624, |inp| { + matroska_permutation((many1(uint(0x66FC)), uint(0x66BF), uint(0x66A5)))(inp).and_then( + |(i, t)| { + Ok(( + i, + TrackTranslate { + edition_uid: value_error(0x66FC, t.0)?, + codec: value_error(0x66BF, t.1)?, + track_id: value_error(0x66A5, t.2)?, + }, + )) + }, + ) })(input) } @@ -604,7 +601,7 @@ pub struct TrackOperation { } pub fn track_operation(input: &[u8]) -> EbmlResult { - ebml_master(0xE2, |i| { + master(0xE2, |i| { map( matroska_permutation((complete(track_combine_planes), complete(track_join_blocks))), |t| TrackOperation { @@ -621,7 +618,7 @@ pub struct TrackCombinePlanes { } pub fn track_combine_planes(input: &[u8]) -> EbmlResult { - ebml_master(0xE3, |i| { + master(0xE3, |i| { map(many1(complete(track_plane)), |v| TrackCombinePlanes { track_planes: v, })(i) @@ -635,18 +632,16 @@ pub struct TrackPlane { } pub fn track_plane(input: &[u8]) -> EbmlResult { - ebml_master(0xE4, |inp| { - matroska_permutation((complete(ebml_uint(0xE5)), complete(ebml_uint(0xE6))))(inp).and_then( - |(i, t)| { - Ok(( - i, - TrackPlane { - uid: value_error(0xE5, t.0)?, - plane_type: value_error(0xE6, t.1)?, - }, - )) - }, - ) + master(0xE4, |inp| { + matroska_permutation((uint(0xE5), uint(0xE6)))(inp).and_then(|(i, t)| { + Ok(( + i, + TrackPlane { + uid: value_error(0xE5, t.0)?, + plane_type: value_error(0xE6, t.1)?, + }, + )) + }) })(input) } @@ -656,10 +651,8 @@ pub struct TrackJoinBlocks { } pub fn track_join_blocks(input: &[u8]) -> EbmlResult { - ebml_master(0xE9, |i| { - map(many1(complete(ebml_uint(0xED))), |v| TrackJoinBlocks { - uid: v, - })(i) + master(0xE9, |i| { + map(many1(uint(0xED)), |v| TrackJoinBlocks { uid: v })(i) })(input) } @@ -669,7 +662,7 @@ pub struct ContentEncodings { } pub fn content_encodings(input: &[u8]) -> EbmlResult { - ebml_master(0x6D80, |i| { + master(0x6D80, |i| { map(many1(complete(content_encoding)), |v| ContentEncodings { content_encoding: v, })(i) @@ -686,11 +679,11 @@ pub struct ContentEncoding { } pub fn content_encoding(input: &[u8]) -> EbmlResult { - ebml_master(0x6240, |inp| { + master(0x6240, |inp| { matroska_permutation(( - complete(ebml_uint(0x5031)), - complete(ebml_uint(0x5032)), - complete(ebml_uint(0x5033)), + uint(0x5031), + uint(0x5032), + uint(0x5033), complete(content_compression), complete(content_encryption), ))(inp) @@ -716,17 +709,16 @@ pub struct ContentCompression { } pub fn content_compression(input: &[u8]) -> EbmlResult { - ebml_master(0x5034, |inp| { - matroska_permutation((complete(ebml_uint(0x4254)), complete(ebml_uint(0x4255))))(inp) - .and_then(|(i, t)| { - Ok(( - i, - ContentCompression { - algo: value_error(0x4254, t.0)?, - settings: t.1, - }, - )) - }) + master(0x5034, |inp| { + matroska_permutation((uint(0x4254), uint(0x4255)))(inp).and_then(|(i, t)| { + Ok(( + i, + ContentCompression { + algo: value_error(0x4254, t.0)?, + settings: t.1, + }, + )) + }) })(input) } @@ -741,15 +733,15 @@ pub struct ContentEncryption { } pub fn content_encryption(input: &[u8]) -> EbmlResult { - ebml_master(0x5035, |i| { + master(0x5035, |i| { map( matroska_permutation(( - complete(ebml_uint(0x47E1)), - complete(ebml_binary(0x47E2)), - complete(ebml_binary(0x47E3)), - complete(ebml_binary(0x47E4)), - complete(ebml_uint(0x47E5)), - complete(ebml_uint(0x47E6)), + uint(0x47E1), + binary(0x47E2), + binary(0x47E3), + binary(0x47E4), + uint(0x47E5), + uint(0x47E6), )), |t| ContentEncryption { enc_algo: t.0, @@ -773,13 +765,13 @@ pub struct Audio { } pub fn audio(input: &[u8]) -> EbmlResult