Add more SWF3 opcodes
This commit is contained in:
parent
98664cd2b9
commit
ddf6de2fe2
|
@ -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)]
|
||||
|
|
|
@ -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> },
|
||||
}
|
|
@ -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)]
|
||||
|
|
|
@ -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]),
|
||||
] }
|
Loading…
Reference in New Issue