Skip to main content

flash_lso/
write.rs

1//! Handles writing of LSO files
2use std::io::Write;
3
4#[cfg(feature = "amf3")]
5use crate::FORMAT_VERSION_AMF3;
6#[cfg(feature = "amf3")]
7use crate::amf3::write::AMF3Encoder;
8use crate::errors::Error;
9use crate::nom_utils::write_string;
10use crate::types::{AMFVersion, Header, Lso};
11use crate::{FORMAT_VERSION_AMF0, HEADER_SIGNATURE, HEADER_VERSION, PADDING};
12
13/// Handles writing a given LSO
14#[derive(Default)]
15pub struct Writer {
16    /// The encoder used for writing Value::AMF3() wrapped types
17    #[cfg(feature = "amf3")]
18    pub amf3_encoder: AMF3Encoder,
19}
20
21impl Writer {
22    /// Write a given LSO
23    pub fn write_full<'a, 'b: 'a, W: Write + 'a>(
24        &'a mut self,
25        writer: &mut W,
26        lso: &'b mut Lso,
27    ) -> std::io::Result<()> {
28        let mut buffer = Vec::new();
29        if lso.header.format_version == AMFVersion::AMF0 {
30            crate::amf0::write::write_body(&mut buffer, &lso.body)?;
31        } else {
32            #[cfg(feature = "amf3")]
33            self.amf3_encoder.write_body(&mut buffer, &lso.body)?;
34        }
35
36        lso.header.length = buffer.len() as u32 + header_length(&lso.header) as u32;
37
38        write_header(writer, &lso.header)?;
39        writer.write_all(&buffer)?;
40        Ok(())
41    }
42}
43
44fn write_header<'a, 'b: 'a, W: Write + 'a>(
45    writer: &mut W,
46    header: &'b Header,
47) -> std::io::Result<()> {
48    writer.write_all(&HEADER_VERSION)?;
49    writer.write_u32(header.length)?;
50    writer.write_all(&HEADER_SIGNATURE)?;
51    write_string(writer, &header.name)?;
52    writer.write_all(&PADDING)?;
53    writer.write_all(&PADDING)?;
54    writer.write_all(&PADDING)?;
55    match header.format_version {
56        AMFVersion::AMF0 => writer.write_all(&[FORMAT_VERSION_AMF0])?,
57        #[cfg(feature = "amf3")]
58        AMFVersion::AMF3 => writer.write_all(&[FORMAT_VERSION_AMF3])?,
59    };
60    Ok(())
61}
62
63/// Get the serialized length of the header in bytes, this does not include the size of the header length field or the lso version marker
64pub fn header_length(header: &Header) -> usize {
65    // signature + (name size u16 + name_len) + 3*padding + amf_version_marker
66    10 + (2 + header.name.len() + 3 + 1)
67}
68
69/// Write a LSO to a vec of bytes
70pub fn write_to_bytes<'a>(lso: &mut Lso) -> Result<Vec<u8>, Error<'a>> {
71    let mut v = Vec::new();
72
73    let mut s = Writer::default();
74    s.write_full(&mut v, lso)
75        .map_err(|e| Error::IoError(e.to_string(), e.kind()))?;
76    Ok(v)
77}
78
79pub(crate) trait WriteExt {
80    fn write_u8(&mut self, value: u8) -> std::io::Result<()>;
81    fn write_u16(&mut self, value: u16) -> std::io::Result<()>;
82    fn write_u32(&mut self, value: u32) -> std::io::Result<()>;
83    fn write_i32(&mut self, value: i32) -> std::io::Result<()>;
84    fn write_f64(&mut self, value: f64) -> std::io::Result<()>;
85}
86
87impl<T> WriteExt for T
88where
89    T: Write,
90{
91    fn write_u8(&mut self, value: u8) -> std::io::Result<()> {
92        self.write_all(&[value])
93    }
94
95    fn write_u16(&mut self, value: u16) -> std::io::Result<()> {
96        self.write_all(&value.to_be_bytes())
97    }
98
99    fn write_u32(&mut self, value: u32) -> std::io::Result<()> {
100        self.write_all(&value.to_be_bytes())
101    }
102
103    fn write_i32(&mut self, value: i32) -> std::io::Result<()> {
104        self.write_all(&value.to_be_bytes())
105    }
106
107    fn write_f64(&mut self, value: f64) -> std::io::Result<()> {
108        self.write_all(&value.to_be_bytes())
109    }
110}