Skip to content

Commit

Permalink
Ref: #1 Return an error instead of panic when parsing unsupported hei…
Browse files Browse the repository at this point in the history
…f files
  • Loading branch information
mindeng committed Feb 23, 2024
1 parent 728ad4a commit 6adbaa3
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 15 deletions.
32 changes: 18 additions & 14 deletions src/bbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use nom::{
bytes::{complete, streaming},
combinator::{fail, map_res},
error::context,
number, AsChar, IResult,
number, AsChar, IResult, Needed,
};

mod idat;
Expand Down Expand Up @@ -188,8 +188,14 @@ where
break Ok((rem, header));
}

if remain.len() < header.body_size() as usize {
return Err(nom::Err::Incomplete(Needed::new(
header.body_size() as usize - remain.len(),
)));
}

// skip box body
remain = &remain[(header.box_size - header.header_size as u64) as usize..];
remain = &remain[header.body_size() as usize..];
}
}

Expand Down Expand Up @@ -276,25 +282,23 @@ fn parse_cstr(input: &[u8]) -> IResult<&[u8], String> {
}

pub fn get_ftyp(input: &[u8]) -> crate::Result<Option<&[u8]>> {
let (remain, header) = travel_header(input, |h, _| {
// MOV files that extracted from HEIC starts with `wide` & `mdat` atoms
h.box_type != "ftyp" && h.box_type != "mdat"
})?;

assert!(header.box_type == "ftyp" || header.box_type == "mdat");
let (_, bbox) = BoxHolder::parse(input).map_err(|_| "parse ftyp failed")?;

if header.box_type == "ftyp" {
if header.body_size() < 4 {
if bbox.box_type() == "ftyp" {
if bbox.body_data().len() < 4 {
return Err(format!(
"Invalid ftyp box; body size should greater than 4, got {}",
header.body_size()
"parse ftyp failed; body size should greater than 4, got {}",
bbox.body_data().len()
)
.into());
}
let (_, ftyp) = streaming::take(4 as usize)(remain)?;
let (_, ftyp) = complete::take(4 as usize)(bbox.body_data())?;
Ok(Some(ftyp))
} else {
} else if bbox.box_type() == "wide" {
// MOV files that extracted from HEIC starts with `wide` & `mdat` atoms
Ok(None)
} else {
Err(format!("parse ftyp failed; first box type is: {}", bbox.box_type()).into())
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/heif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ pub fn parse_heif_exif<R: Read + Seek>(mut reader: R) -> crate::Result<Option<Ex
Err("file is empty")?;
}

let Some(ftyp) = get_ftyp(&buf)? else {
let Some(ftyp) = get_ftyp(&buf).map_err(|e| format!("unsupported HEIF/HEIC file; {}", e))?
else {
return Err(format!("unsupported HEIF/HEIC file; ftyp not found").into());
};
if !HEIF_FTYPS.contains(&ftyp) {
Expand Down Expand Up @@ -198,6 +199,12 @@ mod tests {
);
}

#[test_case("ramdisk.img")]
fn invalid_heic(path: &str) {
let reader = open_sample(path).unwrap();
parse_heif_exif(reader).expect_err("should be ParseFailed error");
}

#[test_case("no-exif.heic", 0x24-10)]
#[test_case("exif.heic", 0xa3a-10)]
fn heic_exif_data(path: &str, exif_size: usize) {
Expand Down
Binary file added testdata/ramdisk.img
Binary file not shown.

0 comments on commit 6adbaa3

Please sign in to comment.