1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::complete::tag::parse_tag_body;
use nom::number::streaming::{le_u16 as parse_le_u16, le_u32 as parse_le_u32};
use nom::IResult as NomResult;
use std::convert::TryFrom;
use swf_types as ast;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum StreamingTagError {
IncompleteHeader,
IncompleteTag(usize),
}
pub(crate) fn parse_tag(input: &[u8], swf_version: u8) -> Result<(&[u8], Option<ast::Tag>), StreamingTagError> {
let base_input = input;
let (input, header) = match parse_tag_header(input) {
Ok(ok) => ok,
Err(_) => return Err(StreamingTagError::IncompleteHeader),
};
if header.code == 0 {
return Ok((&[], None));
}
let body_len = usize::try_from(header.length).unwrap();
if input.len() < body_len {
let header_len = base_input.len() - input.len();
let tag_len = header_len + body_len;
return Err(StreamingTagError::IncompleteTag(tag_len));
}
let (tag_body, input) = input.split_at(body_len);
let tag = parse_tag_body(tag_body, header.code, swf_version);
Ok((input, Some(tag)))
}
pub(crate) fn parse_tag_header(input: &[u8]) -> NomResult<&[u8], ast::TagHeader> {
let (input, code_and_length) = parse_le_u16(input)?;
let code = code_and_length >> 6;
let max_length = (1 << 6) - 1;
let length = code_and_length & max_length;
let (input, length) = if length < max_length {
(input, u32::from(length))
} else {
debug_assert_eq!(length, max_length);
parse_le_u32(input)?
};
Ok((input, ast::TagHeader { code, length }))
}