avm1_parser/
avm1.rs

1use crate::basic_data_types::{parse_c_string, parse_le32_f64};
2use avm1_types as avm1;
3use avm1_types::{FunctionFlags, raw};
4use nom::number::complete::{
5  le_f32 as parse_le_f32, le_i16 as parse_le_i16, le_i32 as parse_le_i32, le_u16 as parse_le_u16, le_u8 as parse_u8,
6};
7use nom::{IResult as NomResult, Needed};
8use std::num::NonZeroUsize;
9
10#[derive(Debug, PartialEq, Eq)]
11pub struct ActionHeader {
12  pub code: u8,
13  pub length: usize,
14}
15
16// TODO: Use nom::cond
17pub fn parse_action_header(input: &[u8]) -> NomResult<&[u8], ActionHeader> {
18  match parse_u8(input) {
19    Ok((remaining_input, action_code)) => {
20      if action_code < 0x80 {
21        Ok((
22          remaining_input,
23          ActionHeader {
24            code: action_code,
25            length: 0,
26          },
27        ))
28      } else {
29        parse_le_u16(remaining_input).map(|(i, length)| {
30          (
31            i,
32            ActionHeader {
33              code: action_code,
34              length: length as usize,
35            },
36          )
37        })
38      }
39    }
40    Err(e) => Err(e),
41  }
42}
43
44pub fn parse_goto_frame_action(input: &[u8]) -> NomResult<&[u8], raw::GotoFrame> {
45  let (input, frame) = parse_le_u16(input)?;
46  Ok((input, raw::GotoFrame { frame }))
47}
48
49pub fn parse_get_url_action(input: &[u8]) -> NomResult<&[u8], raw::GetUrl> {
50  let (input, url) = parse_c_string(input)?;
51  let (input, target) = parse_c_string(input)?;
52  Ok((input, raw::GetUrl { url, target }))
53}
54
55pub fn parse_store_register_action(input: &[u8]) -> NomResult<&[u8], raw::StoreRegister> {
56  let (input, register) = parse_u8(input)?;
57  Ok((input, raw::StoreRegister { register }))
58}
59
60pub fn parse_strict_mode_action(input: &[u8]) -> NomResult<&[u8], raw::StrictMode> {
61  let (input, is_strict) = parse_u8(input)?;
62  Ok((
63    input,
64    raw::StrictMode {
65      is_strict: is_strict != 0,
66    },
67  ))
68}
69
70pub fn parse_constant_pool_action(input: &[u8]) -> NomResult<&[u8], raw::ConstantPool> {
71  use nom::multi::count;
72  let (input, const_count) = parse_le_u16(input)?;
73  let (input, pool) = count(parse_c_string, usize::from(const_count))(input)?;
74  Ok((input, raw::ConstantPool { pool }))
75}
76
77pub fn parse_wait_for_frame_action(input: &[u8]) -> NomResult<&[u8], raw::WaitForFrame> {
78  let (input, frame) = parse_le_u16(input)?;
79  let (input, skip) = parse_u8(input)?;
80  Ok((input, raw::WaitForFrame { frame, skip }))
81}
82
83pub fn parse_set_target_action(input: &[u8]) -> NomResult<&[u8], raw::SetTarget> {
84  let (input, target_name) = parse_c_string(input)?;
85  Ok((input, raw::SetTarget { target_name }))
86}
87
88pub fn parse_goto_label_action(input: &[u8]) -> NomResult<&[u8], raw::GoToLabel> {
89  let (input, label) = parse_c_string(input)?;
90  Ok((input, raw::GoToLabel { label }))
91}
92
93pub fn parse_wait_for_frame2_action(input: &[u8]) -> NomResult<&[u8], raw::WaitForFrame2> {
94  let (input, skip) = parse_u8(input)?;
95  Ok((input, raw::WaitForFrame2 { skip }))
96}
97
98#[derive(Debug, PartialEq, Eq)]
99struct DefineFunction2Flags {
100  pub preload_parent: bool,
101  pub preload_root: bool,
102  pub suppress_super: bool,
103  pub preload_super: bool,
104  pub suppress_arguments: bool,
105  pub preload_arguments: bool,
106  pub suppress_this: bool,
107  pub preload_this: bool,
108  pub preload_global: bool,
109}
110
111// TODO(demurgos): registerCount
112
113pub fn parse_define_function2_action(input: &[u8]) -> NomResult<&[u8], raw::DefineFunction2> {
114  use nom::multi::count;
115
116  let (input, name) = parse_c_string(input)?;
117  let (input, parameter_count) = parse_le_u16(input)?;
118  let (input, register_count) = parse_u8(input)?;
119
120  let (input, flag_bits) = parse_le_u16(input)?;
121  let flags = FunctionFlags::from_bits_truncate(flag_bits);
122
123  let (input, parameters) = count(parse_parameter, usize::from(parameter_count))(input)?;
124  fn parse_parameter(input: &[u8]) -> NomResult<&[u8], avm1::Parameter> {
125    let (input, register) = parse_u8(input)?;
126    let (input, name) = parse_c_string(input)?;
127    Ok((input, avm1::Parameter { register, name }))
128  }
129
130  let (input, body_size) = parse_le_u16(input)?;
131
132  Ok((
133    input,
134    raw::DefineFunction2 {
135      name,
136      register_count,
137      flags,
138      parameters,
139      body_size,
140    },
141  ))
142}
143
144pub fn parse_try_action(input: &[u8]) -> NomResult<&[u8], raw::Try> {
145  let (input, flags) = parse_u8(input)?;
146  let has_catch_block = (flags & (1 << 0)) != 0;
147  let has_finally_block = (flags & (1 << 1)) != 0;
148  let catch_in_register = (flags & (1 << 2)) != 0;
149  // Skip bits [3, 7]
150
151  let (input, r#try) = parse_le_u16(input)?;
152  let (input, catch_size) = parse_le_u16(input)?;
153  let (input, finally_size) = parse_le_u16(input)?;
154
155  let (input, catch_target) = parse_catch_target(input, catch_in_register)?;
156  fn parse_catch_target(input: &[u8], catch_in_register: bool) -> NomResult<&[u8], avm1::CatchTarget> {
157    use nom::combinator::map;
158    if catch_in_register {
159      map(parse_u8, avm1::CatchTarget::Register)(input)
160    } else {
161      map(parse_c_string, avm1::CatchTarget::Variable)(input)
162    }
163  }
164
165  let catch: Option<raw::CatchBlock> = if has_catch_block {
166    Some(raw::CatchBlock {
167      target: catch_target,
168      size: catch_size,
169    })
170  } else {
171    None
172  };
173
174  let finally = if has_finally_block { Some(finally_size) } else { None };
175
176  Ok((input, raw::Try { r#try, catch, finally }))
177}
178
179pub fn parse_with_action(input: &[u8]) -> NomResult<&[u8], raw::With> {
180  let (input, size) = parse_le_u16(input)?;
181
182  Ok((input, raw::With { size }))
183}
184
185pub fn parse_push_action(mut input: &[u8]) -> NomResult<&[u8], raw::Push> {
186  let mut values: Vec<avm1::PushValue> = Vec::new();
187  while !input.is_empty() {
188    let (next_input, value) = parse_push_value(input)?;
189    values.push(value);
190    input = next_input;
191  }
192  Ok((input, raw::Push { values }))
193}
194
195fn parse_push_value(input: &[u8]) -> NomResult<&[u8], avm1::PushValue> {
196  use nom::combinator::map;
197  let (input, code) = parse_u8(input)?;
198  match code {
199    0 => map(parse_c_string, avm1::PushValue::String)(input),
200    1 => map(parse_le_f32, avm1::PushValue::Float32)(input),
201    2 => Ok((input, avm1::PushValue::Null)),
202    3 => Ok((input, avm1::PushValue::Undefined)),
203    4 => map(parse_u8, avm1::PushValue::Register)(input),
204    5 => map(parse_u8, |v| avm1::PushValue::Boolean(v != 0))(input),
205    6 => map(parse_le32_f64, avm1::PushValue::Float64)(input),
206    7 => map(parse_le_i32, avm1::PushValue::Sint32)(input),
207    8 => map(parse_u8, |v| avm1::PushValue::Constant(u16::from(v)))(input),
208    9 => map(parse_le_u16, avm1::PushValue::Constant)(input),
209    _ => Err(nom::Err::Error(nom::error::Error::new(
210      input,
211      nom::error::ErrorKind::Switch,
212    ))),
213  }
214}
215
216pub fn parse_jump_action(input: &[u8]) -> NomResult<&[u8], raw::Jump> {
217  let (input, offset) = parse_le_i16(input)?;
218  Ok((input, raw::Jump { offset }))
219}
220
221pub fn parse_get_url2_action(input: &[u8]) -> NomResult<&[u8], raw::GetUrl2> {
222  let (input, flags) = parse_u8(input)?;
223  let load_variables = (flags & (1 << 0)) != 0;
224  let load_target = (flags & (1 << 1)) != 0;
225  // Skip bits [2, 5]
226  let method_code = flags >> 6;
227
228  let method = match method_code {
229    0 => avm1::GetUrl2Method::None,
230    1 => avm1::GetUrl2Method::Get,
231    2 => avm1::GetUrl2Method::Post,
232    _ => {
233      return Err(nom::Err::Error(nom::error::Error::new(
234        input,
235        nom::error::ErrorKind::Switch,
236      )))
237    }
238  };
239
240  Ok((
241    input,
242    raw::GetUrl2 {
243      method,
244      load_target,
245      load_variables,
246    },
247  ))
248}
249
250pub fn parse_define_function_action(input: &[u8]) -> NomResult<&[u8], raw::DefineFunction> {
251  use nom::multi::count;
252  let (input, name) = parse_c_string(input)?;
253  let (input, param_count) = parse_le_u16(input)?;
254  let (input, parameters) = count(parse_c_string, param_count.into())(input)?;
255  let (input, body_size) = parse_le_u16(input)?;
256
257  Ok((
258    input,
259    raw::DefineFunction {
260      name,
261      parameters,
262      body_size,
263    },
264  ))
265}
266
267pub fn parse_if_action(input: &[u8]) -> NomResult<&[u8], raw::If> {
268  let (input, offset) = parse_le_i16(input)?;
269  Ok((input, raw::If { offset }))
270}
271
272pub fn parse_goto_frame2_action(input: &[u8]) -> NomResult<&[u8], raw::GotoFrame2> {
273  use nom::combinator::cond;
274  let (input, flags) = parse_u8(input)?;
275  let play = (flags & (1 << 0)) != 0;
276  let has_scene_bias = (flags & (1 << 1)) != 0;
277  // Skip bits [2, 7]
278  let (input, scene_bias) = cond(has_scene_bias, parse_le_u16)(input)?;
279
280  Ok((
281    input,
282    raw::GotoFrame2 {
283      play,
284      scene_bias: scene_bias.unwrap_or_default(),
285    },
286  ))
287}
288
289// TODO: Return `(&[u8], ast::Action)` (the function should never fail)
290pub fn parse_action(input: &[u8]) -> NomResult<&[u8], raw::Action> {
291  let base_input = input; // Keep original input to compute lengths.
292
293  let (input, header) = parse_action_header(input)?;
294
295  let body_len = header.length;
296  if input.len() < body_len {
297    let header_len = base_input.len() - input.len();
298    let action_len = header_len + body_len;
299    return Err(nom::Err::Incomplete(Needed::Size(
300      NonZeroUsize::new(action_len).unwrap(),
301    )));
302  }
303  let (action_body, input) = input.split_at(body_len);
304  let action = parse_action_body(action_body, header.code);
305  Ok((input, action))
306}
307
308fn parse_action_body(input: &[u8], code: u8) -> raw::Action {
309  use nom::combinator::map;
310  let result = match code {
311    0x00 => Ok((input, raw::Action::End)),
312    0x04 => Ok((input, raw::Action::NextFrame)),
313    0x05 => Ok((input, raw::Action::PrevFrame)),
314    0x06 => Ok((input, raw::Action::Play)),
315    0x07 => Ok((input, raw::Action::Stop)),
316    0x08 => Ok((input, raw::Action::ToggleQuality)),
317    0x09 => Ok((input, raw::Action::StopSounds)),
318    0x0a => Ok((input, raw::Action::Add)),
319    0x0b => Ok((input, raw::Action::Subtract)),
320    0x0c => Ok((input, raw::Action::Multiply)),
321    0x0d => Ok((input, raw::Action::Divide)),
322    0x0e => Ok((input, raw::Action::Equals)),
323    0x0f => Ok((input, raw::Action::Less)),
324    0x10 => Ok((input, raw::Action::And)),
325    0x11 => Ok((input, raw::Action::Or)),
326    0x12 => Ok((input, raw::Action::Not)),
327    0x13 => Ok((input, raw::Action::StringEquals)),
328    0x14 => Ok((input, raw::Action::StringLength)),
329    0x15 => Ok((input, raw::Action::StringExtract)),
330    0x17 => Ok((input, raw::Action::Pop)),
331    0x18 => Ok((input, raw::Action::ToInteger)),
332    0x1c => Ok((input, raw::Action::GetVariable)),
333    0x1d => Ok((input, raw::Action::SetVariable)),
334    0x20 => Ok((input, raw::Action::SetTarget2)),
335    0x21 => Ok((input, raw::Action::StringAdd)),
336    0x22 => Ok((input, raw::Action::GetProperty)),
337    0x23 => Ok((input, raw::Action::SetProperty)),
338    0x24 => Ok((input, raw::Action::CloneSprite)),
339    0x25 => Ok((input, raw::Action::RemoveSprite)),
340    0x26 => Ok((input, raw::Action::Trace)),
341    0x27 => Ok((input, raw::Action::StartDrag)),
342    0x28 => Ok((input, raw::Action::EndDrag)),
343    0x29 => Ok((input, raw::Action::StringLess)),
344    0x2a => Ok((input, raw::Action::Throw)),
345    0x2b => Ok((input, raw::Action::CastOp)),
346    0x2c => Ok((input, raw::Action::ImplementsOp)),
347    0x2d => Ok((input, raw::Action::FsCommand2)),
348    0x30 => Ok((input, raw::Action::RandomNumber)),
349    0x31 => Ok((input, raw::Action::MbStringLength)),
350    0x32 => Ok((input, raw::Action::CharToAscii)),
351    0x33 => Ok((input, raw::Action::AsciiToChar)),
352    0x34 => Ok((input, raw::Action::GetTime)),
353    0x35 => Ok((input, raw::Action::MbStringExtract)),
354    0x36 => Ok((input, raw::Action::MbCharToAscii)),
355    0x37 => Ok((input, raw::Action::MbAsciiToChar)),
356    0x3a => Ok((input, raw::Action::Delete)),
357    0x3b => Ok((input, raw::Action::Delete2)),
358    0x3c => Ok((input, raw::Action::DefineLocal)),
359    0x3d => Ok((input, raw::Action::CallFunction)),
360    0x3e => Ok((input, raw::Action::Return)),
361    0x3f => Ok((input, raw::Action::Modulo)),
362    0x40 => Ok((input, raw::Action::NewObject)),
363    0x41 => Ok((input, raw::Action::DefineLocal2)),
364    0x42 => Ok((input, raw::Action::InitArray)),
365    0x43 => Ok((input, raw::Action::InitObject)),
366    0x44 => Ok((input, raw::Action::TypeOf)),
367    0x45 => Ok((input, raw::Action::TargetPath)),
368    0x46 => Ok((input, raw::Action::Enumerate)),
369    0x47 => Ok((input, raw::Action::Add2)),
370    0x48 => Ok((input, raw::Action::Less2)),
371    0x49 => Ok((input, raw::Action::Equals2)),
372    0x4a => Ok((input, raw::Action::ToNumber)),
373    0x4b => Ok((input, raw::Action::ToString)),
374    0x4c => Ok((input, raw::Action::PushDuplicate)),
375    0x4d => Ok((input, raw::Action::StackSwap)),
376    0x4e => Ok((input, raw::Action::GetMember)),
377    0x4f => Ok((input, raw::Action::SetMember)),
378    0x50 => Ok((input, raw::Action::Increment)),
379    0x51 => Ok((input, raw::Action::Decrement)),
380    0x52 => Ok((input, raw::Action::CallMethod)),
381    0x53 => Ok((input, raw::Action::NewMethod)),
382    0x54 => Ok((input, raw::Action::InstanceOf)),
383    0x55 => Ok((input, raw::Action::Enumerate2)),
384    0x60 => Ok((input, raw::Action::BitAnd)),
385    0x61 => Ok((input, raw::Action::BitOr)),
386    0x62 => Ok((input, raw::Action::BitXor)),
387    0x63 => Ok((input, raw::Action::BitLShift)),
388    0x64 => Ok((input, raw::Action::BitRShift)),
389    0x65 => Ok((input, raw::Action::BitURShift)),
390    0x66 => Ok((input, raw::Action::StrictEquals)),
391    0x67 => Ok((input, raw::Action::Greater)),
392    0x68 => Ok((input, raw::Action::StringGreater)),
393    0x69 => Ok((input, raw::Action::Extends)),
394    0x81 => map(parse_goto_frame_action, raw::Action::GotoFrame)(input),
395    0x83 => map(parse_get_url_action, |a| raw::Action::GetUrl(Box::new(a)))(input),
396    0x87 => map(parse_store_register_action, raw::Action::StoreRegister)(input),
397    0x88 => map(parse_constant_pool_action, raw::Action::ConstantPool)(input),
398    0x89 => map(parse_strict_mode_action, raw::Action::StrictMode)(input),
399    0x8a => map(parse_wait_for_frame_action, raw::Action::WaitForFrame)(input),
400    0x8b => map(parse_set_target_action, raw::Action::SetTarget)(input),
401    0x8c => map(parse_goto_label_action, raw::Action::GotoLabel)(input),
402    0x8d => map(parse_wait_for_frame2_action, raw::Action::WaitForFrame2)(input),
403    0x8e => map(parse_define_function2_action, |a| raw::Action::DefineFunction2(Box::new(a)))(input),
404    0x8f => map(parse_try_action, |a|raw::Action::Try(Box::new(a)))(input),
405    0x94 => map(parse_with_action, raw::Action::With)(input),
406    0x96 => map(parse_push_action, raw::Action::Push)(input),
407    0x99 => map(parse_jump_action, raw::Action::Jump)(input),
408    0x9a => map(parse_get_url2_action, raw::Action::GetUrl2)(input),
409    0x9b => map(parse_define_function_action, |a|raw::Action::DefineFunction(Box::new(a)))(input),
410    0x9d => map(parse_if_action, raw::Action::If)(input),
411    0x9e => Ok((input, raw::Action::Call)),
412    0x9f => map(parse_goto_frame2_action, raw::Action::GotoFrame2)(input),
413    _ => Ok((
414      &[][..],
415      raw::Action::Raw(Box::new(raw::Raw {
416        code,
417        data: input.to_vec(),
418      })),
419    )),
420  };
421  match result {
422    Ok((_, action)) => action,
423    Err(_) => raw::Action::Error(raw::Error { error: None }),
424  }
425}
426
427#[cfg(test)]
428mod tests {
429  use super::*;
430  use avm1_types::PushValue;
431
432  #[test]
433  fn test_parse_push_action() {
434    {
435      let input = vec![0x04, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x08, 0x02];
436      let actual = parse_push_action(&input[..]);
437      let expected = Ok((
438        &[][..],
439        raw::Push {
440          values: vec![PushValue::Register(0), PushValue::Sint32(1), PushValue::Constant(2)],
441        },
442      ));
443      assert_eq!(actual, expected);
444    }
445    {
446      let input = vec![0x00, 0x00];
447      let actual = parse_push_action(&input[..]);
448      let expected = Ok((
449        &[][..],
450        raw::Push {
451          values: vec![PushValue::String(String::from(""))],
452        },
453      ));
454      assert_eq!(actual, expected);
455    }
456    {
457      let input = vec![0x00, 0x01, 0x00];
458      let actual = parse_push_action(&input[..]);
459      let expected = Ok((
460        &[][..],
461        raw::Push {
462          values: vec![PushValue::String(String::from("\x01"))],
463        },
464      ));
465      assert_eq!(actual, expected);
466    }
467  }
468
469  #[test]
470  fn test_parse_action_header() {
471    {
472      let input = vec![0b00000000, 0b00000000, 0b00000000, 0b00000000];
473      assert_eq!(
474        parse_action_header(&input[..]),
475        Ok((&input[1..], ActionHeader { code: 0x00, length: 0 }))
476      );
477    }
478    {
479      let input = vec![0b00000001, 0b00000000, 0b00000000, 0b00000000];
480      assert_eq!(
481        parse_action_header(&input[..]),
482        Ok((&input[1..], ActionHeader { code: 0x01, length: 0 }))
483      );
484    }
485    {
486      let input = vec![0b00010000, 0b00000000, 0b00000000, 0b00000000];
487      assert_eq!(
488        parse_action_header(&input[..]),
489        Ok((&input[1..], ActionHeader { code: 0x10, length: 0 }))
490      );
491    }
492    {
493      let input = vec![0b10000000, 0b00000000, 0b00000000, 0b00000000];
494      assert_eq!(
495        parse_action_header(&input[..]),
496        Ok((&input[3..], ActionHeader { code: 0x80, length: 0 }))
497      );
498    }
499    {
500      let input = vec![0b10000000, 0b00000001, 0b00000000, 0b00000000];
501      assert_eq!(
502        parse_action_header(&input[..]),
503        Ok((&input[3..], ActionHeader { code: 0x80, length: 1 }))
504      );
505    }
506    {
507      let input = vec![0b10000000, 0b00000000, 0b00000001, 0b00000000];
508      assert_eq!(
509        parse_action_header(&input[..]),
510        Ok((
511          &input[3..],
512          ActionHeader {
513            code: 0x80,
514            length: 256,
515          }
516        ))
517      );
518    }
519  }
520
521  #[test]
522  fn test_parse_action() {
523    {
524      let input = vec![0b00000001, 0b00000000, 0b00000000, 0b00000000];
525      assert_eq!(
526        parse_action(&input),
527        Ok((
528          &input[1..],
529          raw::Action::Raw(Box::new(raw::Raw {
530            code: 0x01,
531            data: Vec::new(),
532          }))
533        ))
534      );
535    }
536    {
537      let input = vec![0b10000000, 0b00000001, 0b00000000, 0b00000011];
538      assert_eq!(
539        parse_action(&input[..]),
540        Ok((
541          &input[4..],
542          raw::Action::Raw(Box::new(raw::Raw {
543            code: 0x80,
544            data: vec![0x03],
545          }))
546        ))
547      );
548    }
549    {
550      let input = vec![0b10000000, 0b00000010, 0b00000000, 0b00000011];
551      assert_eq!(
552        parse_action(&input[..]),
553        Err(::nom::Err::Incomplete(nom::Needed::Size(NonZeroUsize::new(5).unwrap())))
554      );
555    }
556  }
557}