Skip to main content

flash_lso/
read.rs

1use std::convert::TryInto;
2
3use nom::branch::alt;
4use nom::bytes::complete::tag;
5use nom::number::complete::be_u32;
6
7use crate::amf0;
8use crate::amf0::read::AMF0Decoder;
9#[cfg(feature = "amf3")]
10use crate::amf3::read::AMF3Decoder;
11use crate::errors::Error;
12use crate::nom_utils::AMFResult;
13use crate::types::{AMFVersion, Header, Lso};
14use nom::Parser;
15use nom::combinator::all_consuming;
16
17const HEADER_VERSION: [u8; 2] = [0x00, 0xbf];
18const HEADER_SIGNATURE: [u8; 10] = [0x54, 0x43, 0x53, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00];
19const PADDING: [u8; 1] = [0x00];
20
21const FORMAT_VERSION_AMF0: u8 = 0x0;
22
23#[cfg(feature = "amf3")]
24const FORMAT_VERSION_AMF3: u8 = 0x3;
25
26/// The main entry point of decoding an LSO file
27/// Example of use
28/// ```
29/// use std::fs::File;
30/// use std::io::Read;
31/// use flash_lso::read::Reader;
32/// let mut x = File::open("tests/sol/AS2-Demo.sol").expect("Couldn't open file");
33/// let mut data = Vec::new();
34/// let _ = x.read_to_end(&mut data).expect("Unable to read file");
35/// let d = Reader::default().parse(&data).expect("Failed to parse lso file");
36/// println!("{:#?}", d);
37/// ```
38/// }
39#[derive(Default)]
40pub struct Reader {
41    #[cfg(feature = "amf3")]
42    /// Handles reading Amf3 data
43    pub amf3_decoder: AMF3Decoder,
44
45    /// Handles reading Amf0 data
46    pub amf0_decoder: AMF0Decoder,
47}
48
49impl Reader {
50    /// Read a Lso header from the given slice
51    pub fn parse_header<'a>(&self, i: &'a [u8]) -> AMFResult<'a, Header> {
52        let (i, _) = tag(HEADER_VERSION.as_slice())(i)?;
53        let (i, l) = be_u32(i)?;
54        let (i, _) = tag(HEADER_SIGNATURE.as_slice())(i)?;
55
56        let (i, name) = amf0::read::parse_string(i)?;
57
58        let (i, _) = tag(PADDING.as_slice())(i)?;
59        let (i, _) = tag(PADDING.as_slice())(i)?;
60        let (i, _) = tag(PADDING.as_slice())(i)?;
61
62        let (i, version) = alt((
63            tag([FORMAT_VERSION_AMF0].as_slice()),
64            #[cfg(feature = "amf3")]
65            tag([FORMAT_VERSION_AMF3].as_slice()),
66        ))
67        .parse(i)?;
68
69        // This unwrap can't fail because of the alt above
70        let format_version: AMFVersion = version[0].try_into().expect("Invalid version");
71
72        Ok((
73            i,
74            Header {
75                length: l,
76                name: name.to_string(),
77                format_version,
78            },
79        ))
80    }
81
82    /// Read a given buffer as an Lso
83    ///
84    /// Unlike parse, this function will not error if the entire slice isn't consumed
85    /// and will return the data that was not parsed
86    pub fn parse_incomplete<'a>(&mut self, i: &'a [u8]) -> AMFResult<'a, Lso> {
87        let (i, header) = self.parse_header(i)?;
88        match header.format_version {
89            AMFVersion::AMF0 => {
90                let (i, body) = self.amf0_decoder.parse_body(i)?;
91                Ok((i, Lso { header, body }))
92            }
93
94            #[cfg(feature = "amf3")]
95            AMFVersion::AMF3 => {
96                let (i, body) = self.amf3_decoder.parse_body(i)?;
97                Ok((i, Lso { header, body }))
98            }
99        }
100    }
101
102    /// Read a given slice as an Lso
103    ///
104    /// This function will return an error if the slice could not be parsed or if the entire slice
105    /// was not consumed
106    pub fn parse<'a>(&mut self, i: &'a [u8]) -> Result<Lso, nom::Err<Error<'a>>> {
107        let (_, lso) = all_consuming(|i| self.parse_incomplete(i)).parse(i)?;
108        Ok(lso)
109    }
110}