use std::fmt::{Debug, Formatter};
use crate::{
debug::*,
parser::{Error, SuperBox},
BoxType,
};
#[derive(Clone, Eq, PartialEq)]
pub struct DataBox<'a> {
pub tbox: BoxType,
pub data: &'a [u8],
pub original: &'a [u8],
}
impl<'a> DataBox<'a> {
pub fn from_slice(original: &'a [u8]) -> Result<(Self, &'a [u8]), Error> {
if original.len() < 4 {
return Err(Error::Incomplete(4 - original.len()));
}
let len = u32::from_be_bytes([original[0], original[1], original[2], original[3]]);
let i = &original[4..];
let (i, tbox): (&'a [u8], BoxType) = if i.len() >= 4 {
let (tbox, i) = i.split_at(4);
(i, tbox.into())
} else {
return Err(Error::Incomplete(4 - i.len()));
};
let (i, len, original_len) = match len {
0 => (i, i.len(), original.len()),
1 => {
if i.len() < 8 {
return Err(Error::Incomplete(8 - i.len()));
}
let len = u64::from_be_bytes([i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]]);
let i = &i[8..];
if len >= 16 {
(i, len as usize - 16, len as usize)
} else {
return Err(Error::InvalidBoxLength(len as u32));
}
}
2..=7 => {
return Err(Error::InvalidBoxLength(len));
}
len => (i, len as usize - 8, len as usize),
};
if i.len() >= len {
let (data, i) = i.split_at(len);
Ok((
Self {
tbox,
data,
original: &original[0..original_len],
},
i,
))
} else {
Err(Error::Incomplete(len - i.len()))
}
}
pub fn offset_within_superbox(&self, super_box: &SuperBox) -> Option<usize> {
let sbox_as_ptr = super_box.original.as_ptr() as usize;
let self_as_ptr = self.data.as_ptr() as usize;
if self_as_ptr < sbox_as_ptr {
return None;
}
let offset = self_as_ptr.wrapping_sub(sbox_as_ptr);
if offset + self.data.len() > super_box.original.len() {
None
} else {
Some(offset)
}
}
}
impl<'a> Debug for DataBox<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
f.debug_struct("DataBox")
.field("tbox", &self.tbox)
.field("data", &DebugByteSlice(self.data))
.field("original", &DebugByteSlice(self.original))
.finish()
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
#![allow(clippy::panic)]
#![allow(clippy::unwrap_used)]
use hex_literal::hex;
use pretty_assertions_sorted::assert_eq;
use crate::{
box_type::DESCRIPTION_BOX_TYPE,
parser::{DataBox, Error},
};
#[test]
fn simple_box() {
let jumbf = hex!(
"00000026" "6a756d64" "00000000000000000000000000000000" "03" "746573742e64657363626f7800" );
let (boxx, rem) = DataBox::from_slice(&jumbf).unwrap();
assert!(rem.is_empty());
assert_eq!(
boxx,
DataBox {
tbox: DESCRIPTION_BOX_TYPE,
data: &[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 116, 101, 115, 116, 46, 100,
101, 115, 99, 98, 111, 120, 0,
],
original: &jumbf,
}
);
assert_eq!(format!("{boxx:#?}"), "DataBox {\n tbox: b\"jumd\",\n data: 30 bytes starting with [00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 03, 74, 65, 73],\n original: 38 bytes starting with [00, 00, 00, 26, 6a, 75, 6d, 64, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00],\n}");
}
#[test]
fn error_incomplete_box_length() {
let jumbf = hex!(
"000002" );
assert_eq!(
DataBox::from_slice(&jumbf).unwrap_err(),
Error::Incomplete(1)
);
}
#[test]
fn error_incomplete_box_type() {
let jumbf = hex!(
"00000026" "6a756d" );
assert_eq!(
DataBox::from_slice(&jumbf).unwrap_err(),
Error::Incomplete(1)
);
}
#[test]
fn error_invalid_box_length() {
let jumbf = hex!(
"00000002" "6A756D62" );
assert_eq!(
DataBox::from_slice(&jumbf).unwrap_err(),
Error::InvalidBoxLength(2)
);
}
#[test]
fn read_to_eof() {
let jumbf = hex!(
"00000000" "6a756d64" "00000000000000000000000000000000" "03" "746573742e64657363626f7800" );
let (boxx, rem) = DataBox::from_slice(&jumbf).unwrap();
assert!(rem.is_empty());
assert_eq!(
boxx,
DataBox {
tbox: DESCRIPTION_BOX_TYPE,
data: &[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 116, 101, 115, 116, 46, 100,
101, 115, 99, 98, 111, 120, 0,
],
original: &jumbf,
}
);
}
#[test]
fn read_xlbox_size() {
let jumbf = hex!(
"00000001" "6a756d64" "000000000000002e" "00000000000000000000000000000000" "03" "746573742e64657363626f7800" );
let (boxx, rem) = DataBox::from_slice(&jumbf).unwrap();
assert!(rem.is_empty());
assert_eq!(
boxx,
DataBox {
tbox: DESCRIPTION_BOX_TYPE,
data: &[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 116, 101, 115, 116, 46, 100,
101, 115, 99, 98, 111, 120, 0,
],
original: &jumbf,
}
);
}
#[test]
fn error_xlbox_size_too_small() {
let jumbf = hex!(
"00000001" "6a756d64" "000000000000000e" "00000000000000000000000000000000" "03" "746573742e64657363626f7800" );
assert_eq!(
DataBox::from_slice(&jumbf).unwrap_err(),
Error::InvalidBoxLength(14)
);
}
#[test]
fn error_incorrect_length() {
let jumbf = hex!(
"00000026" "6a756d64" "00000000000000000000000000000000" "03" );
assert_eq!(
DataBox::from_slice(&jumbf).unwrap_err(),
Error::Incomplete(13)
);
}
mod offset_within_superbox {
use hex_literal::hex;
use pretty_assertions_sorted::assert_eq;
use crate::parser::SuperBox;
#[test]
fn abuse_read_to_eof() {
let jumbf = hex!(
"00000000" "6a756d62" "00000028" "6a756d64" "6332637300110010800000aa00389b71" "03" "633270612e7369676e617475726500" "00000000" "75756964" "6332637300110010800000aa00389b717468697320776f756c64206e6f726d616c6c792062652062696e617279207369676e617475726520646174612e2e2e" );
let (sbox_full, rem) = SuperBox::from_slice(&jumbf).unwrap();
assert!(rem.is_empty());
assert_eq!(sbox_full.original.len(), 119);
let (sbox_short, rem) = SuperBox::from_slice(&jumbf[0..118]).unwrap();
assert!(rem.is_empty());
assert_eq!(sbox_short.original.len(), 118);
let dbox_from_full = sbox_full.data_box().unwrap();
assert_eq!(
dbox_from_full.offset_within_superbox(&sbox_full).unwrap(),
56
);
assert!(dbox_from_full.offset_within_superbox(&sbox_short).is_none());
let dbox_as_child = sbox_full.child_boxes.first().unwrap();
assert!(dbox_as_child.as_super_box().is_none());
let dbox_as_child = dbox_as_child.as_data_box().unwrap();
assert_eq!(dbox_from_full, dbox_as_child);
}
#[test]
fn dbox_precedes_sbox() {
let jumbf = hex!(
"00000267" "6a756d62" "0000001e" "6a756d64" "6332706100110010800000aa00389b71" "03" "6332706100" "00000241" "6a756d62" "00000024" "6a756d64" "63326d6100110010800000aa00389b71" "03" "63622e61646f62655f3100" "0000008f" "6a756d62" "00000029" "6a756d64" "6332617300110010800000aa00389b71" "03" "633270612e617373657274696f6e7300" "0000005e" "6a756d62" "0000002d" "6a756d64" "6a736f6e00110010800000aa00389b71" "03" "633270612e6c6f636174696f6e2e62726f616400"
"00000029" "6a736f6e" "7b20226c6f636174696f6e223a20224d61726761"
"746520436974792c204e4a227d" "0000010f" "6a756d62" "00000024" "6a756d64" "6332636c00110010800000aa00389b71" "03" "633270612e636c61696d00" "000000e3" "6a736f6e" "7b0a2020202020202020202020202272"
"65636f7264657222203a202250686f74"
"6f73686f70222c0a2020202020202020"
"20202020227369676e61747572652220"
"3a202273656c66236a756d62663d735f"
"61646f62655f31222c0a202020202020"
"20202020202022617373657274696f6e"
"7322203a205b0a202020202020202020"
"202020202020202273656c66236a756d"
"62663d61735f61646f62655f312f6332"
"70612e6c6f636174696f6e2e62726f61"
"643f686c3d3736313432424436323336"
"3346220a202020202020202020202020"
"5d0a20202020202020207d" "00000077" "6a756d62" "00000028" "6a756d64" "6332637300110010800000aa00389b71" "03" "633270612e7369676e617475726500" "00000047" "75756964" "6332637300110010800000aa00389b71"
"7468697320776f756c64206e6f726d61"
"6c6c792062652062696e617279207369"
"676e617475726520646174612e2e2e"
);
let (sbox, rem) = SuperBox::from_slice(&jumbf).unwrap();
assert!(rem.is_empty());
let claim_dbox = sbox
.find_by_label("cb.adobe_1/c2pa.claim")
.unwrap()
.data_box()
.unwrap();
let sig_sbox = sbox
.find_by_label("cb.adobe_1")
.unwrap()
.child_boxes
.get(2)
.unwrap();
assert!(sig_sbox.as_data_box().is_none());
let sig_sbox = sig_sbox.as_super_box().unwrap();
assert!(claim_dbox.offset_within_superbox(sig_sbox).is_none());
}
}
}