swf_parser/complete/
movie.rs1use std::fmt;
2
3use crate::complete::parse_tag;
4use crate::streaming::movie::parse_swf_signature;
5use crate::streaming::decompress;
6use ast::CompressionMethod;
7use nom::IResult as NomResult;
8use swf_types as ast;
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum SwfParseError {
18 InvalidSignature,
24
25 UnsupportedCompression(CompressionMethod),
29
30 InvalidPayload,
36
37 InvalidHeader,
42}
43
44impl std::error::Error for SwfParseError {}
45
46impl fmt::Display for SwfParseError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 SwfParseError::InvalidSignature => f.write_str("invalid SWF signature"),
50 SwfParseError::UnsupportedCompression(comp) => {
51 f.write_str("unsupported SWF compression: ")?;
52 fmt::Debug::fmt(comp, f)
53 }
54 SwfParseError::InvalidPayload => f.write_str("invalid SWF payload"),
55 SwfParseError::InvalidHeader => f.write_str("invalid SWF header"),
56 }
57 }
58}
59
60pub fn parse_swf(input: &[u8]) -> Result<ast::Movie, SwfParseError> {
66 let (input, signature) = match parse_swf_signature(input) {
67 Ok(ok) => ok,
68 Err(_) => return Err(SwfParseError::InvalidSignature),
69 };
70
71 let result = match signature.compression_method {
72 CompressionMethod::None => decompress::decompress_none(input),
73 #[cfg(feature="deflate")]
74 CompressionMethod::Deflate => decompress::decompress_zlib(input),
75 #[cfg(feature="lzma")]
76 CompressionMethod::Lzma => decompress::decompress_lzma(input),
77 #[allow(unreachable_patterns)]
78 method => return Err(SwfParseError::UnsupportedCompression(method)),
79 };
80
81 let (_input, payload) = result.map_err(|_| SwfParseError::InvalidPayload)?;
82
83 match parse_movie(&payload, signature.swf_version) {
87 Ok((_, movie)) => Ok(movie),
88 Err(_) => Err(SwfParseError::InvalidHeader),
89 }
90}
91
92fn parse_movie(input: &[u8], swf_version: u8) -> NomResult<&[u8], ast::Movie> {
96 let (input, header) = parse_header(input, swf_version)?;
97 let tags = parse_tag_block_string(input, swf_version);
98
99 Ok((&[][..], ast::Movie { header, tags }))
100}
101
102fn parse_header(input: &[u8], swf_version: u8) -> NomResult<&[u8], ast::Header> {
104 match crate::streaming::movie::parse_header(input, swf_version) {
105 Ok(ok) => Ok(ok),
106 Err(nom::Err::Incomplete(_)) => Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Complete))),
107 Err(e) => Err(e),
108 }
109}
110
111pub(crate) fn parse_tag_block_string(mut input: &[u8], swf_version: u8) -> Vec<ast::Tag> {
113 let mut tags: Vec<ast::Tag> = Vec::new();
114 loop {
115 input = match parse_tag(input, swf_version) {
116 (input, Some(tag)) => {
117 tags.push(tag);
118 input
119 }
120 (_, None) => return tags,
121 }
122 }
123}