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