Add more SWF3 opcodes

This commit is contained in:
Mike Welsh 2016-11-05 19:44:49 -07:00
parent 98664cd2b9
commit ddf6de2fe2
4 changed files with 61 additions and 3 deletions

View File

@ -1,7 +1,7 @@
use avm1::types::Action;
use avm1::opcode::OpCode;
use byteorder::{LittleEndian, ReadBytesExt};
use std::io::{Read, Result};
use std::io::{Error, ErrorKind, Read, Result};
pub struct Reader<R: Read> {
inner: R,
@ -30,13 +30,24 @@ impl<R: Read> Reader<R> {
let action = match OpCode::from_u8(opcode) {
Some(OpCode::End) => return Ok(None),
Some(OpCode::GetUrl) => Action::GetUrl {
url: try!(action_reader.read_c_string()),
target: try!(action_reader.read_c_string()),
},
Some(OpCode::GotoFrame) => {
let frame = try!(action_reader.inner.read_u16::<LittleEndian>());
Action::GotoFrame(frame)
},
Some(OpCode::NextFrame) => Action::NextFrame,
Some(OpCode::Play) => Action::Play,
Some(OpCode::PreviousFrame) => Action::PreviousFrame,
Some(OpCode::Stop) => Action::Stop,
Some(OpCode::StopSounds) => Action::StopSounds,
Some(OpCode::ToggleQuality) => Action::ToggleQuality,
Some(OpCode::WaitForFrame) => Action::WaitForFrame {
frame: try!(action_reader.inner.read_u16::<LittleEndian>()),
num_actions_to_skip: try!(action_reader.inner.read_u8()),
},
_ => {
let mut data = Vec::with_capacity(length);
try!(action_reader.inner.read_to_end(&mut data));
@ -54,6 +65,21 @@ impl<R: Read> Reader<R> {
} else { 0 };
Ok((opcode, length))
}
fn read_c_string(&mut self) -> Result<String> {
let mut bytes = Vec::new();
loop {
let byte = try!(self.inner.read_u8());
if byte == 0 {
break;
}
bytes.push(byte)
}
// TODO: There is probably a better way to do this.
// TODO: Verify ANSI for SWF 5 and earlier.
String::from_utf8(bytes)
.map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid string data"))
}
}
#[cfg(test)]

View File

@ -1,10 +1,13 @@
#[derive(Debug,PartialEq)]
pub enum Action {
GetUrl { url: String, target: String },
GotoFrame(u16),
NextFrame,
Play,
PreviousFrame,
Stop,
StopSounds,
ToggleQuality,
WaitForFrame { frame: u16, num_actions_to_skip: u8 },
Unknown { opcode: u8, data: Vec<u8> },
}

View File

@ -23,12 +23,26 @@ impl<W: Write> Writer<W> {
pub fn write_action(&mut self, action: &Action) -> Result<()> {
match action {
&Action::GetUrl { ref url, ref target } => {
try!(self.write_action_header(OpCode::GetUrl, url.len() + target.len() + 2));
try!(self.write_c_string(url));
try!(self.write_c_string(target));
},
&Action::GotoFrame(frame) => {
try!(self.write_action_header(OpCode::GotoFrame, 2));
try!(self.inner.write_u16::<LittleEndian>(frame));
},
&Action::NextFrame => try!(self.write_action_header(OpCode::NextFrame, 0)),
&Action::Play => try!(self.write_action_header(OpCode::Play, 0)),
&Action::PreviousFrame => try!(self.write_action_header(OpCode::PreviousFrame, 0)),
&Action::Stop => try!(self.write_action_header(OpCode::Stop, 0)),
&Action::StopSounds => try!(self.write_action_header(OpCode::StopSounds, 0)),
&Action::ToggleQuality => try!(self.write_action_header(OpCode::ToggleQuality, 0)),
&Action::WaitForFrame { frame, num_actions_to_skip } => {
try!(self.write_action_header(OpCode::WaitForFrame, 3));
try!(self.inner.write_u16::<LittleEndian>(frame));
try!(self.inner.write_u8(num_actions_to_skip));
},
&Action::Unknown { opcode, ref data } => {
try!(self.write_opcode_and_length(opcode, data.len()));
try!(self.inner.write_all(&data));
@ -50,6 +64,11 @@ impl<W: Write> Writer<W> {
}
Ok(())
}
fn write_c_string(&mut self, s: &str) -> Result<()> {
try!(self.inner.write_all(s.as_bytes()));
self.inner.write_u8(0)
}
}
#[cfg(test)]

View File

@ -803,9 +803,19 @@ pub fn tag_tests() -> Vec<TagTestData> { vec![
] }
pub fn avm1_tests() -> Vec<Avm1TestData> { vec![
(
3,
Action::GetUrl { url: String::from("a"), target: String::from("b") },
vec![0x83, 4, 0, 97, 0, 98, 0]
),
(3, Action::GotoFrame(11), vec![0x81, 2, 0, 11, 0]),
(3, Action::NextFrame, vec![0x04]),
(3, Action::Play, vec![0x06]),
(3, Action::PreviousFrame, vec![0x05]),
(3, Action::Stop, vec![0x07]),
(3, Action::StopSounds, vec![0x09]),
(3, Action::ToggleQuality, vec![0x08]),
(3, Action::WaitForFrame { frame: 4, num_actions_to_skip: 10 }, vec![0x8A, 3, 0, 4, 0, 10]),
(1, Action::Unknown { opcode: 0x79, data: vec![] }, vec![0x79]),
(1, Action::Unknown { opcode: 0xA0, data: vec![2, 3] }, vec![0xA0, 2, 0, 2, 3]),
] }