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
use nom::{IResult as NomResult, Needed};
use crate::parsers::header::{parse_header, parse_swf_signature};
use crate::parsers::tags::parse_swf_tag;
use crate::state::ParseState;
use swf_tree as ast;

pub fn parse_tag_block_string<'a>(input: &'a [u8], state: &mut ParseState) -> NomResult<&'a [u8], Vec<ast::Tag>> {
  let mut result: Vec<ast::Tag> = Vec::new();
  let mut current_input: &[u8] = input;
  while current_input.len() > 0 {
    // A null byte indicates the end of the string of actions
    if current_input[0] == 0 {
      current_input = &current_input[1..];
      break;
    }
    match parse_swf_tag(current_input, state) {
      Ok((next_input, swf_tag)) => {
        current_input = next_input;
        result.push(swf_tag);
      }
      Err(::nom::Err::Incomplete(_)) => return Err(::nom::Err::Incomplete(Needed::Unknown)),
      Err(e) => return Err(e),
    };
  }
  Ok((current_input, result))
}

pub fn parse_movie_payload(input: &[u8], swf_version: u8) -> NomResult<&[u8], ast::Movie> {
  let mut state = ParseState::new(swf_version);
  do_parse!(
    input,
    header: call!(parse_header, swf_version) >>
    tags: apply!(parse_tag_block_string, &mut state) >>
    (ast::Movie {
      header: header,
      tags: tags,
    })
  )
}

pub fn parse_movie(input: &[u8]) -> NomResult<&[u8], ast::Movie> {
  use ::std::io::Write;

  let (input, signature) = parse_swf_signature(input)?;
  match signature.compression_method {
    ast::CompressionMethod::None => parse_movie_payload(input, signature.swf_version),
    ast::CompressionMethod::Deflate => {
      let mut decoder = ::inflate::InflateWriter::from_zlib(Vec::new());
      decoder.write(input).unwrap();
      let payload = decoder.finish().unwrap();

      match parse_movie_payload(&payload[..], signature.swf_version) {
        Ok((_, movie)) => Ok((&[][..], movie)),
        Err(::nom::Err::Error(::nom::simple_errors::Context::Code(_, e))) => Err(::nom::Err::Error(::nom::simple_errors::Context::Code(&[][..], e))),
        Err(::nom::Err::Failure(::nom::simple_errors::Context::Code(_, e))) => Err(::nom::Err::Failure(::nom::simple_errors::Context::Code(&[][..], e))),
        Err(::nom::Err::Incomplete(n)) => Err(::nom::Err::Incomplete(n)),
      }
    }
    ast::CompressionMethod::Lzma => {
      unimplemented!()
    }
  }
}