Skip to main content

rakata_formats/ssf/
writer.rs

1//! SSF binary writer.
2
3use std::io::{Cursor, Write};
4
5use crate::binary::{checked_to_usize, write_u32};
6
7use super::{Ssf, SsfBinaryError, FILE_HEADER_SIZE, SSF_MAGIC, SSF_VERSION_V11};
8
9/// Writes an SSF file to a writer.
10///
11/// # Errors
12///
13/// [`SsfBinaryError::InvalidHeader`] when the sound-table offset would overlap
14/// the header, which is checked before anything is written, and
15/// [`SsfBinaryError::Io`] when the writer fails. A partial file may already
16/// have been written in the second case.
17pub fn write_ssf<W: Write>(writer: &mut W, ssf: &Ssf) -> Result<(), SsfBinaryError> {
18    let sound_table_offset = checked_to_usize(ssf.sound_table_offset, "sound_table_offset")?;
19    if sound_table_offset < FILE_HEADER_SIZE {
20        return Err(SsfBinaryError::InvalidHeader(
21            "sound table offset overlaps SSF header".into(),
22        ));
23    }
24
25    writer.write_all(&SSF_MAGIC)?;
26    writer.write_all(&SSF_VERSION_V11)?;
27    write_u32(writer, ssf.sound_table_offset)?;
28
29    if sound_table_offset > FILE_HEADER_SIZE {
30        writer.write_all(&vec![0_u8; sound_table_offset - FILE_HEADER_SIZE])?;
31    }
32
33    for strref in &ssf.sounds {
34        writer.write_all(&strref.raw().to_le_bytes())?;
35    }
36
37    for strref in &ssf.reserved_entries {
38        writer.write_all(&strref.raw().to_le_bytes())?;
39    }
40
41    Ok(())
42}
43
44/// Serializes an SSF file into bytes.
45///
46/// # Errors
47///
48/// [`SsfBinaryError::InvalidHeader`] when the sound-table offset would overlap
49/// the header. The `Vec` target has no I/O to fail at.
50pub fn write_ssf_to_vec(ssf: &Ssf) -> Result<Vec<u8>, SsfBinaryError> {
51    let mut cursor = Cursor::new(Vec::new());
52    write_ssf(&mut cursor, ssf)?;
53    Ok(cursor.into_inner())
54}