MP4: Make AtomReader act relatively

This commit is contained in:
Serial 2023-03-13 15:37:31 -04:00 committed by Alex
parent 2271266dd4
commit f422444848

View file

@ -5,6 +5,7 @@ use super::Mp4File;
use crate::error::{ErrorKind, LoftyError, Result}; use crate::error::{ErrorKind, LoftyError, Result};
use crate::macros::{decode_err, err}; use crate::macros::{decode_err, err};
use crate::probe::ParseOptions; use crate::probe::ParseOptions;
use crate::traits::SeekStreamLen;
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
@ -15,6 +16,7 @@ where
R: Read + Seek, R: Read + Seek,
{ {
reader: R, reader: R,
start: u64,
remaining_size: u64, remaining_size: u64,
len: u64, len: u64,
} }
@ -24,18 +26,18 @@ where
R: Read + Seek, R: Read + Seek,
{ {
pub(super) fn new(mut reader: R) -> Result<Self> { pub(super) fn new(mut reader: R) -> Result<Self> {
use crate::traits::SeekStreamLen;
#[allow(unstable_name_collisions)] #[allow(unstable_name_collisions)]
let len = reader.stream_len()?; let len = reader.stream_len()?;
Ok(Self { Ok(Self {
reader, reader,
start: 0,
remaining_size: len, remaining_size: len,
len, len,
}) })
} }
pub(super) fn reset_length(&mut self, len: u64) { pub(super) fn reset_bounds(&mut self, start_position: u64, len: u64) {
self.start = start_position;
self.remaining_size = len; self.remaining_size = len;
self.len = len; self.len = len;
} }
@ -84,13 +86,30 @@ where
{ {
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> { fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
match pos { match pos {
SeekFrom::Start(_) | SeekFrom::End(_) => { SeekFrom::Start(s) => {
let ret = self.reader.seek(pos)?; if s > self.len {
let new_rem = self.len.saturating_sub(ret); self.remaining_size = 0;
self.remaining_size = new_rem; let bound_end = self.start + self.len;
return self.reader.seek(SeekFrom::Start(bound_end));
}
let ret = self.reader.seek(SeekFrom::Start(self.start + s))?;
self.remaining_size = self.len.saturating_sub(ret);
Ok(ret) Ok(ret)
}, },
SeekFrom::End(s) => {
if s.is_positive() || s == 0 {
self.remaining_size = 0;
return self.reader.seek(SeekFrom::Start(self.start + self.len));
}
let bound_end = self.start + self.len;
let relative_seek_count = core::cmp::min(self.len, s.unsigned_abs());
self.reader.seek(SeekFrom::Start(
bound_end.saturating_sub(relative_seek_count),
))
},
SeekFrom::Current(s) => { SeekFrom::Current(s) => {
if s.is_negative() { if s.is_negative() {
self.remaining_size = self.remaining_size.saturating_add(s.unsigned_abs()); self.remaining_size = self.remaining_size.saturating_add(s.unsigned_abs());
@ -102,10 +121,6 @@ where
}, },
} }
} }
fn stream_position(&mut self) -> std::io::Result<u64> {
self.position()
}
} }
impl<R> Read for AtomReader<R> impl<R> Read for AtomReader<R>
@ -154,23 +169,22 @@ where
R: Read + Seek, R: Read + Seek,
{ {
let mut reader = AtomReader::new(data)?; let mut reader = AtomReader::new(data)?;
let file_length = reader.stream_len()?;
let ftyp = verify_mp4(&mut reader)?; let ftyp = verify_mp4(&mut reader)?;
// Find the `moov` atom and restrict the reader to its length // Find the `moov` atom and restrict the reader to its length
let moov_info = Moov::find(&mut reader)?; let moov_info = Moov::find(&mut reader)?;
reader.reset_length(moov_info.len - 8); reader.reset_bounds(moov_info.start + 8, moov_info.len - 8);
let moov = Moov::parse(&mut reader, parse_options.read_properties)?; let moov = Moov::parse(&mut reader, parse_options.read_properties)?;
let file_length = reader.seek(SeekFrom::End(0))?;
Ok(Mp4File { Ok(Mp4File {
ftyp, ftyp,
ilst_tag: moov.meta, ilst_tag: moov.meta,
properties: if parse_options.read_properties { properties: if parse_options.read_properties {
// Remove the length restriction // Remove the length restriction
reader.reset_length(file_length); reader.reset_bounds(0, file_length);
super::properties::read_properties(&mut reader, &moov.traks, file_length)? super::properties::read_properties(&mut reader, &moov.traks, file_length)?
} else { } else {
Mp4Properties::default() Mp4Properties::default()
@ -265,8 +279,6 @@ pub(super) fn meta_is_full<R>(reader: &mut R) -> Result<bool>
where where
R: Read + Seek, R: Read + Seek,
{ {
let meta_pos = reader.stream_position()?;
// A full `meta` atom should have the following: // A full `meta` atom should have the following:
// //
// Version (1) // Version (1)
@ -282,11 +294,11 @@ where
match &possible_ident { match &possible_ident {
b"hdlr" | b"ilst" | b"mhdr" | b"ctry" | b"lang" => { b"hdlr" | b"ilst" | b"mhdr" | b"ctry" | b"lang" => {
reader.seek(SeekFrom::Start(meta_pos))?; reader.seek(SeekFrom::Current(-8))?;
Ok(false) Ok(false)
}, },
_ => { _ => {
reader.seek(SeekFrom::Start(meta_pos + 4))?; reader.seek(SeekFrom::Current(-4))?;
Ok(true) Ok(true)
}, },
} }