use crate::blocks::common::{read_link, BlockHeader, ParseBlock, BLOCK_HEADER_SIZE};
use crate::error::{Mf4Error, Result};
use byteorder::ReadBytesExt;
use std::io::Cursor;
#[derive(Debug, Clone)]
pub struct DgBlock {
pub header: BlockHeader,
pub dg_next: u64,
pub cg_first: u64,
pub data: u64,
pub md_comment: u64,
pub rec_id_size: u8,
pub reserved: [u8; 7],
}
impl DgBlock {
pub const MIN_SIZE: u64 = BLOCK_HEADER_SIZE as u64 + 4 * 8 + 8;
}
impl ParseBlock for DgBlock {
fn parse(data: &[u8], offset: u64) -> Result<Self> {
let header = BlockHeader::parse(data, offset)?;
header.validate_type(b"##DG", offset)?;
if header.length < Self::MIN_SIZE {
return Err(Mf4Error::invalid_block_size(
"DG",
header.length,
Self::MIN_SIZE,
));
}
let links_start = BLOCK_HEADER_SIZE;
let dg_next = read_link(data, links_start)?;
let cg_first = read_link(data, links_start + 8)?;
let data_link = read_link(data, links_start + 16)?;
let md_comment = read_link(data, links_start + 24)?;
let data_start = header.data_offset();
let data_section = data
.get(data_start..)
.ok_or_else(|| Mf4Error::truncated(offset, data_start, data.len()))?;
let mut cursor = Cursor::new(data_section);
let rec_id_size = cursor.read_u8()?;
let mut reserved = [0u8; 7];
std::io::Read::read_exact(&mut cursor, &mut reserved)?;
Ok(DgBlock {
header,
dg_next,
cg_first,
data: data_link,
md_comment,
rec_id_size,
reserved,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_dg_block() -> Vec<u8> {
let mut data = vec![0u8; 64];
data[0..4].copy_from_slice(b"##DG");
data[8..16].copy_from_slice(&64u64.to_le_bytes()); data[16..24].copy_from_slice(&4u64.to_le_bytes());
data[24..32].copy_from_slice(&100u64.to_le_bytes()); data[32..40].copy_from_slice(&200u64.to_le_bytes()); data[40..48].copy_from_slice(&300u64.to_le_bytes()); data[48..56].copy_from_slice(&400u64.to_le_bytes());
data[56] = 0;
data
}
#[test]
fn test_dg_block_parse() {
let data = create_test_dg_block();
let dg = DgBlock::parse(&data, 1000).unwrap();
assert_eq!(dg.header.block_type, *b"##DG");
assert_eq!(dg.dg_next, 100);
assert_eq!(dg.cg_first, 200);
assert_eq!(dg.data, 300);
assert_eq!(dg.md_comment, 400);
assert_eq!(dg.rec_id_size, 0);
}
#[test]
fn test_dg_block_invalid_type() {
let mut data = create_test_dg_block();
data[0..4].copy_from_slice(b"##XX");
let result = DgBlock::parse(&data, 1000);
assert!(matches!(result, Err(Mf4Error::InvalidBlockId { .. })));
}
}