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
16pub 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
111pub 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 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 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 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
289pub fn parse_action(input: &[u8]) -> NomResult<&[u8], raw::Action> {
291 let base_input = input; 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}