Rustfmt pass
This commit is contained in:
parent
64dd94b1db
commit
76c5c2bbc4
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::useless_attribute)]
|
#![allow(clippy::useless_attribute)]
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug,PartialEq,Clone,Copy,FromPrimitive)]
|
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
||||||
pub enum OpCode {
|
pub enum OpCode {
|
||||||
End = 0x00,
|
End = 0x00,
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::unreadable_literal)]
|
#![allow(clippy::unreadable_literal)]
|
||||||
|
|
||||||
use crate::avm1::types::*;
|
|
||||||
use crate::avm1::opcode::OpCode;
|
use crate::avm1::opcode::OpCode;
|
||||||
|
use crate::avm1::types::*;
|
||||||
use crate::read::SwfRead;
|
use crate::read::SwfRead;
|
||||||
use std::io::{Error, ErrorKind, Read, Result};
|
use std::io::{Error, ErrorKind, Read, Result};
|
||||||
|
|
||||||
|
@ -18,10 +18,7 @@ impl<R: Read> SwfRead<R> for Reader<R> {
|
||||||
|
|
||||||
impl<R: Read> Reader<R> {
|
impl<R: Read> Reader<R> {
|
||||||
pub fn new(inner: R, version: u8) -> Reader<R> {
|
pub fn new(inner: R, version: u8) -> Reader<R> {
|
||||||
Reader {
|
Reader { inner, version }
|
||||||
inner,
|
|
||||||
version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_action_list(&mut self) -> Result<Vec<Action>> {
|
pub fn read_action_list(&mut self) -> Result<Vec<Action>> {
|
||||||
|
@ -123,13 +120,17 @@ impl<R: Read> Reader<R> {
|
||||||
}
|
}
|
||||||
OpCode::GotoLabel => Action::GotoLabel(action_reader.read_c_string()?),
|
OpCode::GotoLabel => Action::GotoLabel(action_reader.read_c_string()?),
|
||||||
OpCode::Greater => Action::Greater,
|
OpCode::Greater => Action::Greater,
|
||||||
OpCode::If => Action::If { offset: action_reader.read_i16()? },
|
OpCode::If => Action::If {
|
||||||
|
offset: action_reader.read_i16()?,
|
||||||
|
},
|
||||||
OpCode::ImplementsOp => Action::ImplementsOp,
|
OpCode::ImplementsOp => Action::ImplementsOp,
|
||||||
OpCode::Increment => Action::Increment,
|
OpCode::Increment => Action::Increment,
|
||||||
OpCode::InitArray => Action::InitArray,
|
OpCode::InitArray => Action::InitArray,
|
||||||
OpCode::InitObject => Action::InitObject,
|
OpCode::InitObject => Action::InitObject,
|
||||||
OpCode::InstanceOf => Action::InstanceOf,
|
OpCode::InstanceOf => Action::InstanceOf,
|
||||||
OpCode::Jump => Action::Jump { offset: action_reader.read_i16()? },
|
OpCode::Jump => Action::Jump {
|
||||||
|
offset: action_reader.read_i16()?,
|
||||||
|
},
|
||||||
OpCode::Less => Action::Less,
|
OpCode::Less => Action::Less,
|
||||||
OpCode::Less2 => Action::Less2,
|
OpCode::Less2 => Action::Less2,
|
||||||
OpCode::MBAsciiToChar => Action::MBAsciiToChar,
|
OpCode::MBAsciiToChar => Action::MBAsciiToChar,
|
||||||
|
@ -195,7 +196,9 @@ impl<R: Read> Reader<R> {
|
||||||
(&mut action_reader.inner as &mut Read).take(code_length.into()),
|
(&mut action_reader.inner as &mut Read).take(code_length.into()),
|
||||||
self.version,
|
self.version,
|
||||||
);
|
);
|
||||||
Action::With { actions: with_reader.read_action_list()? }
|
Action::With {
|
||||||
|
actions: with_reader.read_action_list()?,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OpCode::WaitForFrame2 => Action::WaitForFrame2 {
|
OpCode::WaitForFrame2 => Action::WaitForFrame2 {
|
||||||
num_actions_to_skip: action_reader.read_u8()?,
|
num_actions_to_skip: action_reader.read_u8()?,
|
||||||
|
@ -221,10 +224,7 @@ impl<R: Read> Reader<R> {
|
||||||
fn read_unknown_action(&mut self, opcode: u8, length: usize) -> Result<Action> {
|
fn read_unknown_action(&mut self, opcode: u8, length: usize) -> Result<Action> {
|
||||||
let mut data = vec![0u8; length];
|
let mut data = vec![0u8; length];
|
||||||
self.inner.read_exact(&mut data)?;
|
self.inner.read_exact(&mut data)?;
|
||||||
Ok(Action::Unknown {
|
Ok(Action::Unknown { opcode, data })
|
||||||
opcode,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_push_value(&mut self) -> Result<Value> {
|
fn read_push_value(&mut self) -> Result<Value> {
|
||||||
|
@ -363,8 +363,7 @@ pub mod tests {
|
||||||
// Failed, result doesn't match.
|
// Failed, result doesn't match.
|
||||||
panic!(
|
panic!(
|
||||||
"Incorrectly parsed action.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
"Incorrectly parsed action.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
||||||
parsed_action,
|
parsed_action, expected_action
|
||||||
expected_action
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,10 @@ pub enum Action {
|
||||||
GetMember,
|
GetMember,
|
||||||
GetProperty,
|
GetProperty,
|
||||||
GetTime,
|
GetTime,
|
||||||
GetUrl { url: String, target: String },
|
GetUrl {
|
||||||
|
url: String,
|
||||||
|
target: String,
|
||||||
|
},
|
||||||
GetUrl2 {
|
GetUrl2 {
|
||||||
send_vars_method: SendVarsMethod,
|
send_vars_method: SendVarsMethod,
|
||||||
is_target_sprite: bool,
|
is_target_sprite: bool,
|
||||||
|
@ -52,13 +55,17 @@ pub enum Action {
|
||||||
},
|
},
|
||||||
GotoLabel(String),
|
GotoLabel(String),
|
||||||
Greater,
|
Greater,
|
||||||
If { offset: i16 },
|
If {
|
||||||
|
offset: i16,
|
||||||
|
},
|
||||||
ImplementsOp,
|
ImplementsOp,
|
||||||
Increment,
|
Increment,
|
||||||
InitArray,
|
InitArray,
|
||||||
InitObject,
|
InitObject,
|
||||||
InstanceOf,
|
InstanceOf,
|
||||||
Jump { offset: i16 },
|
Jump {
|
||||||
|
offset: i16,
|
||||||
|
},
|
||||||
Less,
|
Less,
|
||||||
Less2,
|
Less2,
|
||||||
MBAsciiToChar,
|
MBAsciiToChar,
|
||||||
|
@ -107,10 +114,20 @@ pub enum Action {
|
||||||
Trace,
|
Trace,
|
||||||
Try(TryBlock),
|
Try(TryBlock),
|
||||||
TypeOf,
|
TypeOf,
|
||||||
WaitForFrame { frame: u16, num_actions_to_skip: u8 },
|
WaitForFrame {
|
||||||
WaitForFrame2 { num_actions_to_skip: u8 },
|
frame: u16,
|
||||||
With { actions: Vec<Action> },
|
num_actions_to_skip: u8,
|
||||||
Unknown { opcode: u8, data: Vec<u8> },
|
},
|
||||||
|
WaitForFrame2 {
|
||||||
|
num_actions_to_skip: u8,
|
||||||
|
},
|
||||||
|
With {
|
||||||
|
actions: Vec<Action>,
|
||||||
|
},
|
||||||
|
Unknown {
|
||||||
|
opcode: u8,
|
||||||
|
data: Vec<u8>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::cyclomatic_complexity, clippy::unreadable_literal)]
|
#![allow(clippy::cyclomatic_complexity, clippy::unreadable_literal)]
|
||||||
|
|
||||||
use crate::avm1::types::*;
|
|
||||||
use crate::avm1::opcode::OpCode;
|
use crate::avm1::opcode::OpCode;
|
||||||
|
use crate::avm1::types::*;
|
||||||
use crate::write::SwfWrite;
|
use crate::write::SwfWrite;
|
||||||
use std::io::{Result, Write};
|
use std::io::{Result, Write};
|
||||||
|
|
||||||
|
@ -18,10 +18,7 @@ impl<W: Write> SwfWrite<W> for Writer<W> {
|
||||||
|
|
||||||
impl<W: Write> Writer<W> {
|
impl<W: Write> Writer<W> {
|
||||||
pub fn new(inner: W, version: u8) -> Writer<W> {
|
pub fn new(inner: W, version: u8) -> Writer<W> {
|
||||||
Writer {
|
Writer { inner, version }
|
||||||
inner,
|
|
||||||
version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_action_list(&mut self, actions: &[Action]) -> Result<()> {
|
pub fn write_action_list(&mut self, actions: &[Action]) -> Result<()> {
|
||||||
|
@ -69,8 +66,12 @@ impl<W: Write> Writer<W> {
|
||||||
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
||||||
fn_writer.write_action_list(actions)?;
|
fn_writer.write_action_list(actions)?;
|
||||||
}
|
}
|
||||||
let len = name.len() + 1 + 2 + params.iter().map(|p| p.len() + 1).sum::<usize>() +
|
let len = name.len()
|
||||||
2 + action_buf.len();
|
+ 1
|
||||||
|
+ 2
|
||||||
|
+ params.iter().map(|p| p.len() + 1).sum::<usize>()
|
||||||
|
+ 2
|
||||||
|
+ action_buf.len();
|
||||||
self.write_action_header(OpCode::DefineFunction, len)?;
|
self.write_action_header(OpCode::DefineFunction, len)?;
|
||||||
self.write_c_string(name)?;
|
self.write_c_string(name)?;
|
||||||
self.write_u16(params.len() as u16)?;
|
self.write_u16(params.len() as u16)?;
|
||||||
|
@ -86,12 +87,16 @@ impl<W: Write> Writer<W> {
|
||||||
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
let mut fn_writer = Writer::new(&mut action_buf, self.version);
|
||||||
fn_writer.write_action_list(&function.actions)?;
|
fn_writer.write_action_list(&function.actions)?;
|
||||||
}
|
}
|
||||||
let len = function.name.len() + 1 + 3 +
|
let len = function.name.len()
|
||||||
function
|
+ 1
|
||||||
|
+ 3
|
||||||
|
+ function
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.name.len() + 2)
|
.map(|p| p.name.len() + 2)
|
||||||
.sum::<usize>() + 4 + action_buf.len();
|
.sum::<usize>()
|
||||||
|
+ 4
|
||||||
|
+ action_buf.len();
|
||||||
let num_registers = function
|
let num_registers = function
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -101,26 +106,25 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_c_string(&function.name)?;
|
self.write_c_string(&function.name)?;
|
||||||
self.write_u16(function.params.len() as u16)?;
|
self.write_u16(function.params.len() as u16)?;
|
||||||
self.write_u8(num_registers)?;
|
self.write_u8(num_registers)?;
|
||||||
let flags =
|
let flags = if function.preload_global {
|
||||||
if function.preload_global {
|
0b1_00000000
|
||||||
0b1_00000000
|
} else {
|
||||||
|
0
|
||||||
|
} | if function.preload_parent {
|
||||||
|
0b10000000
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
} | if function.preload_root { 0b1000000 } else { 0 }
|
||||||
|
| if function.suppress_super { 0b100000 } else { 0 }
|
||||||
|
| if function.preload_super { 0b10000 } else { 0 }
|
||||||
|
| if function.suppress_arguments {
|
||||||
|
0b1000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} |
|
}
|
||||||
if function.preload_parent {
|
| if function.preload_arguments { 0b100 } else { 0 }
|
||||||
0b10000000
|
| if function.suppress_this { 0b10 } else { 0 }
|
||||||
} else {
|
| if function.preload_this { 0b1 } else { 0 };
|
||||||
0
|
|
||||||
} | if function.preload_root { 0b1000000 } else { 0 } |
|
|
||||||
if function.suppress_super { 0b100000 } else { 0 } |
|
|
||||||
if function.preload_super { 0b10000 } else { 0 } |
|
|
||||||
if function.suppress_arguments {
|
|
||||||
0b1000
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
} | if function.preload_arguments { 0b100 } else { 0 } |
|
|
||||||
if function.suppress_this { 0b10 } else { 0 } |
|
|
||||||
if function.preload_this { 0b1 } else { 0 };
|
|
||||||
self.write_u16(flags)?;
|
self.write_u16(flags)?;
|
||||||
for param in &function.params {
|
for param in &function.params {
|
||||||
self.write_u8(if let Some(n) = param.register_index {
|
self.write_u8(if let Some(n) = param.register_index {
|
||||||
|
@ -162,12 +166,12 @@ impl<W: Write> Writer<W> {
|
||||||
} => {
|
} => {
|
||||||
self.write_action_header(OpCode::GetUrl2, 1)?;
|
self.write_action_header(OpCode::GetUrl2, 1)?;
|
||||||
let flags = (match send_vars_method {
|
let flags = (match send_vars_method {
|
||||||
SendVarsMethod::None => 0,
|
SendVarsMethod::None => 0,
|
||||||
SendVarsMethod::Get => 1,
|
SendVarsMethod::Get => 1,
|
||||||
SendVarsMethod::Post => 2,
|
SendVarsMethod::Post => 2,
|
||||||
} << 6) |
|
} << 6)
|
||||||
if is_target_sprite { 0b10 } else { 0 } |
|
| if is_target_sprite { 0b10 } else { 0 }
|
||||||
if is_load_vars { 0b1 } else { 0 };
|
| if is_load_vars { 0b1 } else { 0 };
|
||||||
self.write_u8(flags)?;
|
self.write_u8(flags)?;
|
||||||
}
|
}
|
||||||
Action::GetVariable => self.write_action_header(OpCode::GetVariable, 0)?,
|
Action::GetVariable => self.write_action_header(OpCode::GetVariable, 0)?,
|
||||||
|
@ -228,8 +232,7 @@ impl<W: Write> Writer<W> {
|
||||||
.map(|v| match *v {
|
.map(|v| match *v {
|
||||||
Value::Str(ref string) => string.len() + 2,
|
Value::Str(ref string) => string.len() + 2,
|
||||||
Value::Null | Value::Undefined => 1,
|
Value::Null | Value::Undefined => 1,
|
||||||
Value::Register(_) |
|
Value::Register(_) | Value::Bool(_) => 2,
|
||||||
Value::Bool(_) => 2,
|
|
||||||
Value::Double(_) => 9,
|
Value::Double(_) => 9,
|
||||||
Value::Float(_) | Value::Int(_) => 5,
|
Value::Float(_) | Value::Int(_) => 5,
|
||||||
Value::ConstantPool(v) => {
|
Value::ConstantPool(v) => {
|
||||||
|
@ -299,8 +302,9 @@ impl<W: Write> Writer<W> {
|
||||||
}
|
}
|
||||||
finally_length = fn_writer.inner.len() - (try_length + catch_length);
|
finally_length = fn_writer.inner.len() - (try_length + catch_length);
|
||||||
}
|
}
|
||||||
let len = 7 + action_buf.len() +
|
let len = 7
|
||||||
if let Some((CatchVar::Var(ref name), _)) = try_block.catch {
|
+ action_buf.len()
|
||||||
|
+ if let Some((CatchVar::Var(ref name), _)) = try_block.catch {
|
||||||
name.len() + 1
|
name.len() + 1
|
||||||
} else {
|
} else {
|
||||||
1
|
1
|
||||||
|
@ -311,8 +315,8 @@ impl<W: Write> Writer<W> {
|
||||||
0b100
|
0b100
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if try_block.finally.is_some() { 0b10 } else { 0 } |
|
} | if try_block.finally.is_some() { 0b10 } else { 0 }
|
||||||
if try_block.catch.is_some() { 0b1 } else { 0 },
|
| if try_block.catch.is_some() { 0b1 } else { 0 },
|
||||||
)?;
|
)?;
|
||||||
self.write_u16(try_length as u16)?;
|
self.write_u16(try_length as u16)?;
|
||||||
self.write_u16(catch_length as u16)?;
|
self.write_u16(catch_length as u16)?;
|
||||||
|
@ -333,7 +337,9 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_u16(frame)?;
|
self.write_u16(frame)?;
|
||||||
self.write_u8(num_actions_to_skip)?;
|
self.write_u8(num_actions_to_skip)?;
|
||||||
}
|
}
|
||||||
Action::WaitForFrame2 { num_actions_to_skip } => {
|
Action::WaitForFrame2 {
|
||||||
|
num_actions_to_skip,
|
||||||
|
} => {
|
||||||
self.write_action_header(OpCode::WaitForFrame2, 1)?;
|
self.write_action_header(OpCode::WaitForFrame2, 1)?;
|
||||||
self.write_u8(num_actions_to_skip)?;
|
self.write_u8(num_actions_to_skip)?;
|
||||||
}
|
}
|
||||||
|
@ -432,9 +438,7 @@ mod tests {
|
||||||
if written_bytes != expected_bytes {
|
if written_bytes != expected_bytes {
|
||||||
panic!(
|
panic!(
|
||||||
"Error writing action.\nTag:\n{:?}\n\nWrote:\n{:?}\n\nExpected:\n{:?}",
|
"Error writing action.\nTag:\n{:?}\n\nWrote:\n{:?}\n\nExpected:\n{:?}",
|
||||||
action,
|
action, written_bytes, expected_bytes
|
||||||
written_bytes,
|
|
||||||
expected_bytes
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod types;
|
|
||||||
pub mod read;
|
pub mod read;
|
||||||
|
pub mod types;
|
||||||
pub mod write;
|
pub mod write;
|
||||||
|
|
||||||
mod opcode;
|
mod opcode;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::useless_attribute)]
|
#![allow(clippy::useless_attribute)]
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug,PartialEq,Clone,Copy,FromPrimitive)]
|
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
||||||
pub enum OpCode {
|
pub enum OpCode {
|
||||||
Add = 0xA0,
|
Add = 0xA0,
|
||||||
AddI = 0xC5,
|
AddI = 0xC5,
|
||||||
|
|
|
@ -90,10 +90,9 @@ impl<R: Read> Reader<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_i24(&mut self) -> Result<i32> {
|
fn read_i24(&mut self) -> Result<i32> {
|
||||||
Ok(
|
Ok(i32::from(self.read_u8()?)
|
||||||
i32::from(self.read_u8()?) | (i32::from(self.read_u8()?) << 8) |
|
| (i32::from(self.read_u8()?) << 8)
|
||||||
(i32::from(self.read_u8()?) << 16),
|
| (i32::from(self.read_u8()?) << 16))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
fn read_i32(&mut self) -> Result<i32> {
|
fn read_i32(&mut self) -> Result<i32> {
|
||||||
let mut n: i32 = 0;
|
let mut n: i32 = 0;
|
||||||
|
@ -114,7 +113,10 @@ impl<R: Read> Reader<R> {
|
||||||
fn read_string(&mut self) -> Result<String> {
|
fn read_string(&mut self) -> Result<String> {
|
||||||
let len = self.read_u30()? as usize;
|
let len = self.read_u30()? as usize;
|
||||||
let mut s = String::with_capacity(len);
|
let mut s = String::with_capacity(len);
|
||||||
self.inner.by_ref().take(len as u64).read_to_string(&mut s)?;
|
self.inner
|
||||||
|
.by_ref()
|
||||||
|
.take(len as u64)
|
||||||
|
.read_to_string(&mut s)?;
|
||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,10 +354,7 @@ impl<R: Read> Reader<R> {
|
||||||
value: self.read_index()?,
|
value: self.read_index()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Ok(Metadata {
|
Ok(Metadata { name, items })
|
||||||
name,
|
|
||||||
items,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_instance(&mut self) -> Result<Instance> {
|
fn read_instance(&mut self) -> Result<Instance> {
|
||||||
|
@ -877,8 +876,7 @@ pub mod tests {
|
||||||
// Failed, result doesn't match.
|
// Failed, result doesn't match.
|
||||||
panic!(
|
panic!(
|
||||||
"Incorrectly parsed ABC.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
"Incorrectly parsed ABC.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
||||||
parsed,
|
parsed, abc_file
|
||||||
abc_file
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,12 @@ pub enum Multiname {
|
||||||
namespace: Index<Namespace>,
|
namespace: Index<Namespace>,
|
||||||
name: Index<String>,
|
name: Index<String>,
|
||||||
},
|
},
|
||||||
RTQName { name: Index<String> },
|
RTQName {
|
||||||
RTQNameA { name: Index<String> },
|
name: Index<String>,
|
||||||
|
},
|
||||||
|
RTQNameA {
|
||||||
|
name: Index<String>,
|
||||||
|
},
|
||||||
RTQNameL,
|
RTQNameL,
|
||||||
RTQNameLA,
|
RTQNameLA,
|
||||||
Multiname {
|
Multiname {
|
||||||
|
@ -72,8 +76,12 @@ pub enum Multiname {
|
||||||
namespace_set: Index<NamespaceSet>,
|
namespace_set: Index<NamespaceSet>,
|
||||||
name: Index<String>,
|
name: Index<String>,
|
||||||
},
|
},
|
||||||
MultinameL { namespace_set: Index<NamespaceSet> },
|
MultinameL {
|
||||||
MultinameLA { namespace_set: Index<NamespaceSet> },
|
namespace_set: Index<NamespaceSet>,
|
||||||
|
},
|
||||||
|
MultinameLA {
|
||||||
|
namespace_set: Index<NamespaceSet>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -178,10 +186,22 @@ pub enum TraitKind {
|
||||||
type_name: Index<Multiname>,
|
type_name: Index<Multiname>,
|
||||||
value: Option<DefaultValue>,
|
value: Option<DefaultValue>,
|
||||||
},
|
},
|
||||||
Method { disp_id: u32, method: Index<Method> },
|
Method {
|
||||||
Getter { disp_id: u32, method: Index<Method> },
|
disp_id: u32,
|
||||||
Setter { disp_id: u32, method: Index<Method> },
|
method: Index<Method>,
|
||||||
Class { slot_id: u32, class: Index<Class> },
|
},
|
||||||
|
Getter {
|
||||||
|
disp_id: u32,
|
||||||
|
method: Index<Method>,
|
||||||
|
},
|
||||||
|
Setter {
|
||||||
|
disp_id: u32,
|
||||||
|
method: Index<Method>,
|
||||||
|
},
|
||||||
|
Class {
|
||||||
|
slot_id: u32,
|
||||||
|
class: Index<Class>,
|
||||||
|
},
|
||||||
Function {
|
Function {
|
||||||
slot_id: u32,
|
slot_id: u32,
|
||||||
function: Index<Method>,
|
function: Index<Method>,
|
||||||
|
@ -209,14 +229,21 @@ pub struct Script {
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
Add,
|
Add,
|
||||||
AddI,
|
AddI,
|
||||||
AsType { type_name: Index<Multiname> },
|
AsType {
|
||||||
|
type_name: Index<Multiname>,
|
||||||
|
},
|
||||||
AsTypeLate,
|
AsTypeLate,
|
||||||
BitAnd,
|
BitAnd,
|
||||||
BitNot,
|
BitNot,
|
||||||
BitOr,
|
BitOr,
|
||||||
BitXor,
|
BitXor,
|
||||||
Call { num_args: u32 },
|
Call {
|
||||||
CallMethod { index: Index<Method>, num_args: u32 },
|
num_args: u32,
|
||||||
|
},
|
||||||
|
CallMethod {
|
||||||
|
index: Index<Method>,
|
||||||
|
num_args: u32,
|
||||||
|
},
|
||||||
CallProperty {
|
CallProperty {
|
||||||
index: Index<Multiname>,
|
index: Index<Multiname>,
|
||||||
num_args: u32,
|
num_args: u32,
|
||||||
|
@ -229,7 +256,10 @@ pub enum Op {
|
||||||
index: Index<Multiname>,
|
index: Index<Multiname>,
|
||||||
num_args: u32,
|
num_args: u32,
|
||||||
},
|
},
|
||||||
CallStatic { index: Index<Method>, num_args: u32 },
|
CallStatic {
|
||||||
|
index: Index<Method>,
|
||||||
|
num_args: u32,
|
||||||
|
},
|
||||||
CallSuper {
|
CallSuper {
|
||||||
index: Index<Multiname>,
|
index: Index<Multiname>,
|
||||||
num_args: u32,
|
num_args: u32,
|
||||||
|
@ -239,15 +269,21 @@ pub enum Op {
|
||||||
num_args: u32,
|
num_args: u32,
|
||||||
},
|
},
|
||||||
CheckFilter,
|
CheckFilter,
|
||||||
Coerce { index: Index<Multiname> },
|
Coerce {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
CoerceA,
|
CoerceA,
|
||||||
CoerceS,
|
CoerceS,
|
||||||
Construct { num_args: u32 },
|
Construct {
|
||||||
|
num_args: u32,
|
||||||
|
},
|
||||||
ConstructProp {
|
ConstructProp {
|
||||||
index: Index<Multiname>,
|
index: Index<Multiname>,
|
||||||
num_args: u32,
|
num_args: u32,
|
||||||
},
|
},
|
||||||
ConstructSuper { num_args: u32 },
|
ConstructSuper {
|
||||||
|
num_args: u32,
|
||||||
|
},
|
||||||
ConvertB,
|
ConvertB,
|
||||||
ConvertD,
|
ConvertD,
|
||||||
ConvertI,
|
ConvertI,
|
||||||
|
@ -259,31 +295,63 @@ pub enum Op {
|
||||||
register_name: Index<String>,
|
register_name: Index<String>,
|
||||||
register: u8,
|
register: u8,
|
||||||
},
|
},
|
||||||
DebugFile { file_name: Index<String> },
|
DebugFile {
|
||||||
DebugLine { line_num: u32 },
|
file_name: Index<String>,
|
||||||
DecLocal { index: u32 },
|
},
|
||||||
DecLocalI { index: u32 },
|
DebugLine {
|
||||||
|
line_num: u32,
|
||||||
|
},
|
||||||
|
DecLocal {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
DecLocalI {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
Decrement,
|
Decrement,
|
||||||
DecrementI,
|
DecrementI,
|
||||||
DeleteProperty { index: Index<Multiname> },
|
DeleteProperty {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
Divide,
|
Divide,
|
||||||
Dup,
|
Dup,
|
||||||
Dxns { index: Index<String> },
|
Dxns {
|
||||||
|
index: Index<String>,
|
||||||
|
},
|
||||||
DxnsLate,
|
DxnsLate,
|
||||||
Equals,
|
Equals,
|
||||||
EscXAttr,
|
EscXAttr,
|
||||||
EscXElem,
|
EscXElem,
|
||||||
FindProperty { index: Index<Multiname> },
|
FindProperty {
|
||||||
FindPropStrict { index: Index<Multiname> },
|
index: Index<Multiname>,
|
||||||
GetDescendants { index: Index<Multiname> },
|
},
|
||||||
|
FindPropStrict {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
|
GetDescendants {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
GetGlobalScope,
|
GetGlobalScope,
|
||||||
GetGlobalSlot { index: u32 },
|
GetGlobalSlot {
|
||||||
GetLex { index: Index<Multiname> },
|
index: u32,
|
||||||
GetLocal { index: u32 },
|
},
|
||||||
GetProperty { index: Index<Multiname> },
|
GetLex {
|
||||||
GetScopeObject { index: u8 },
|
index: Index<Multiname>,
|
||||||
GetSlot { index: u32 },
|
},
|
||||||
GetSuper { index: Index<Multiname> },
|
GetLocal {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
GetProperty {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
|
GetScopeObject {
|
||||||
|
index: u8,
|
||||||
|
},
|
||||||
|
GetSlot {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
GetSuper {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
GreaterEquals,
|
GreaterEquals,
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
HasNext,
|
HasNext,
|
||||||
|
@ -291,31 +359,71 @@ pub enum Op {
|
||||||
object_register: u32,
|
object_register: u32,
|
||||||
index_register: u32,
|
index_register: u32,
|
||||||
},
|
},
|
||||||
IfEq { offset: i32 },
|
IfEq {
|
||||||
IfFalse { offset: i32 },
|
offset: i32,
|
||||||
IfGe { offset: i32 },
|
},
|
||||||
IfGt { offset: i32 },
|
IfFalse {
|
||||||
IfLe { offset: i32 },
|
offset: i32,
|
||||||
IfLt { offset: i32 },
|
},
|
||||||
IfNge { offset: i32 },
|
IfGe {
|
||||||
IfNgt { offset: i32 },
|
offset: i32,
|
||||||
IfNle { offset: i32 },
|
},
|
||||||
IfNlt { offset: i32 },
|
IfGt {
|
||||||
IfNe { offset: i32 },
|
offset: i32,
|
||||||
IfStrictEq { offset: i32 },
|
},
|
||||||
IfStrictNe { offset: i32 },
|
IfLe {
|
||||||
IfTrue { offset: i32 },
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfLt {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfNge {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfNgt {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfNle {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfNlt {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfNe {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfStrictEq {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfStrictNe {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
|
IfTrue {
|
||||||
|
offset: i32,
|
||||||
|
},
|
||||||
In,
|
In,
|
||||||
IncLocal { index: u32 },
|
IncLocal {
|
||||||
IncLocalI { index: u32 },
|
index: u32,
|
||||||
|
},
|
||||||
|
IncLocalI {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
Increment,
|
Increment,
|
||||||
IncrementI,
|
IncrementI,
|
||||||
InitProperty { index: Index<Multiname> },
|
InitProperty {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
InstanceOf,
|
InstanceOf,
|
||||||
IsType { index: Index<Multiname> },
|
IsType {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
IsTypeLate,
|
IsTypeLate,
|
||||||
Jump { offset: i32 },
|
Jump {
|
||||||
Kill { index: u32 },
|
offset: i32,
|
||||||
|
},
|
||||||
|
Kill {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
Label,
|
Label,
|
||||||
LessEquals,
|
LessEquals,
|
||||||
LessThan,
|
LessThan,
|
||||||
|
@ -330,39 +438,73 @@ pub enum Op {
|
||||||
Negate,
|
Negate,
|
||||||
NegateI,
|
NegateI,
|
||||||
NewActivation,
|
NewActivation,
|
||||||
NewArray { num_args: u32 },
|
NewArray {
|
||||||
NewCatch { index: Index<Exception> },
|
num_args: u32,
|
||||||
NewClass { index: Index<Class> },
|
},
|
||||||
NewFunction { index: Index<Method> },
|
NewCatch {
|
||||||
NewObject { num_args: u32 },
|
index: Index<Exception>,
|
||||||
|
},
|
||||||
|
NewClass {
|
||||||
|
index: Index<Class>,
|
||||||
|
},
|
||||||
|
NewFunction {
|
||||||
|
index: Index<Method>,
|
||||||
|
},
|
||||||
|
NewObject {
|
||||||
|
num_args: u32,
|
||||||
|
},
|
||||||
NextName,
|
NextName,
|
||||||
NextValue,
|
NextValue,
|
||||||
Nop,
|
Nop,
|
||||||
Not,
|
Not,
|
||||||
Pop,
|
Pop,
|
||||||
PopScope,
|
PopScope,
|
||||||
PushByte { value: u8 },
|
PushByte {
|
||||||
PushDouble { value: Index<f64> },
|
value: u8,
|
||||||
|
},
|
||||||
|
PushDouble {
|
||||||
|
value: Index<f64>,
|
||||||
|
},
|
||||||
PushFalse,
|
PushFalse,
|
||||||
PushInt { value: Index<i32> },
|
PushInt {
|
||||||
PushNamespace { value: Index<Namespace> },
|
value: Index<i32>,
|
||||||
|
},
|
||||||
|
PushNamespace {
|
||||||
|
value: Index<Namespace>,
|
||||||
|
},
|
||||||
PushNaN,
|
PushNaN,
|
||||||
PushNull,
|
PushNull,
|
||||||
PushScope,
|
PushScope,
|
||||||
PushShort { value: u32 }, // TODO: Is this really a u30?
|
PushShort {
|
||||||
PushString { value: Index<String> },
|
value: u32,
|
||||||
|
}, // TODO: Is this really a u30?
|
||||||
|
PushString {
|
||||||
|
value: Index<String>,
|
||||||
|
},
|
||||||
PushTrue,
|
PushTrue,
|
||||||
PushUint { value: Index<u32> },
|
PushUint {
|
||||||
|
value: Index<u32>,
|
||||||
|
},
|
||||||
PushUndefined,
|
PushUndefined,
|
||||||
PushWith,
|
PushWith,
|
||||||
ReturnValue,
|
ReturnValue,
|
||||||
ReturnVoid,
|
ReturnVoid,
|
||||||
RShift,
|
RShift,
|
||||||
SetLocal { index: u32 },
|
SetLocal {
|
||||||
SetGlobalSlot { index: u32 },
|
index: u32,
|
||||||
SetProperty { index: Index<Multiname> },
|
},
|
||||||
SetSlot { index: u32 },
|
SetGlobalSlot {
|
||||||
SetSuper { index: Index<Multiname> },
|
index: u32,
|
||||||
|
},
|
||||||
|
SetProperty {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
|
SetSlot {
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
SetSuper {
|
||||||
|
index: Index<Multiname>,
|
||||||
|
},
|
||||||
StrictEquals,
|
StrictEquals,
|
||||||
Subtract,
|
Subtract,
|
||||||
SubtractI,
|
SubtractI,
|
||||||
|
|
|
@ -293,13 +293,12 @@ impl<W: Write> Writer<W> {
|
||||||
}
|
}
|
||||||
self.write_index(&method.name)?;
|
self.write_index(&method.name)?;
|
||||||
self.write_u8(
|
self.write_u8(
|
||||||
if has_param_names { 0x80 } else { 0 } | if method.needs_dxns { 0x40 } else { 0 } |
|
if has_param_names { 0x80 } else { 0 }
|
||||||
if num_optional_params > 0 { 0x08 } else { 0 } | if method.needs_rest {
|
| if method.needs_dxns { 0x40 } else { 0 }
|
||||||
0x04
|
| if num_optional_params > 0 { 0x08 } else { 0 }
|
||||||
} else {
|
| if method.needs_rest { 0x04 } else { 0 }
|
||||||
0
|
| if method.needs_activation { 0x02 } else { 0 }
|
||||||
} | if method.needs_activation { 0x02 } else { 0 } |
|
| if method.needs_arguments_object {
|
||||||
if method.needs_arguments_object {
|
|
||||||
0x01
|
0x01
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
@ -396,11 +395,9 @@ impl<W: Write> Writer<W> {
|
||||||
0x08
|
0x08
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if instance.is_interface { 0x04 } else { 0 } | if instance.is_final {
|
} | if instance.is_interface { 0x04 } else { 0 }
|
||||||
0x02
|
| if instance.is_final { 0x02 } else { 0 }
|
||||||
} else {
|
| if instance.is_sealed { 0x01 } else { 0 },
|
||||||
0
|
|
||||||
} | if instance.is_sealed { 0x01 } else { 0 },
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(ref namespace) = instance.protected_namespace {
|
if let Some(ref namespace) = instance.protected_namespace {
|
||||||
|
@ -442,11 +439,12 @@ impl<W: Write> Writer<W> {
|
||||||
|
|
||||||
fn write_trait(&mut self, t: &Trait) -> Result<()> {
|
fn write_trait(&mut self, t: &Trait) -> Result<()> {
|
||||||
self.write_index(&t.name)?;
|
self.write_index(&t.name)?;
|
||||||
let flags = if !t.metadata.is_empty() { 0b0100_0000 } else { 0 } | if t.is_override {
|
let flags = if !t.metadata.is_empty() {
|
||||||
0b0010_0000
|
0b0100_0000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if t.is_final { 0b0001_0000 } else { 0 };
|
} | if t.is_override { 0b0010_0000 } else { 0 }
|
||||||
|
| if t.is_final { 0b0001_0000 } else { 0 };
|
||||||
|
|
||||||
match t.kind {
|
match t.kind {
|
||||||
TraitKind::Slot {
|
TraitKind::Slot {
|
||||||
|
@ -990,8 +988,7 @@ pub mod tests {
|
||||||
// Failed, result doesn't match.
|
// Failed, result doesn't match.
|
||||||
panic!(
|
panic!(
|
||||||
"Incorrectly written ABC.\nWritten:\n{:?}\n\nExpected:\n{:?}",
|
"Incorrectly written ABC.\nWritten:\n{:?}\n\nExpected:\n{:?}",
|
||||||
out,
|
out, bytes
|
||||||
bytes
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
130
src/read.rs
130
src/read.rs
|
@ -1,9 +1,9 @@
|
||||||
#![allow(clippy::float_cmp, clippy::inconsistent_digit_grouping, clippy::unreadable_literal)]
|
#![allow(clippy::float_cmp, clippy::inconsistent_digit_grouping, clippy::unreadable_literal)]
|
||||||
|
|
||||||
|
use crate::types::*;
|
||||||
use byteorder::{LittleEndian, ReadBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::{Error, ErrorKind, Read, Result};
|
use std::io::{Error, ErrorKind, Read, Result};
|
||||||
use crate::types::*;
|
|
||||||
|
|
||||||
/// Reads SWF data from a stream.
|
/// Reads SWF data from a stream.
|
||||||
pub fn read_swf<R: Read>(input: R) -> Result<Swf> {
|
pub fn read_swf<R: Read>(input: R) -> Result<Swf> {
|
||||||
|
@ -53,18 +53,21 @@ fn make_zlib_reader<'a, R: Read + 'a>(input: R) -> Result<Box<Read + 'a>> {
|
||||||
Ok(Box::new(decoder))
|
Ok(Box::new(decoder))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "flate2",feature = "libflate")))]
|
#[cfg(not(any(feature = "flate2", feature = "libflate")))]
|
||||||
fn make_zlib_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
|
fn make_zlib_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
|
||||||
Err(Error::new(ErrorKind::InvalidData, "Support for Zlib compressed SWFs is not enabled."))
|
Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
"Support for Zlib compressed SWFs is not enabled.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lzma-support")]
|
#[cfg(feature = "lzma-support")]
|
||||||
fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<Read + 'a>> {
|
fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<Read + 'a>> {
|
||||||
// Flash uses a mangled LZMA header, so we have to massage it into the normal
|
// Flash uses a mangled LZMA header, so we have to massage it into the normal
|
||||||
// format.
|
// format.
|
||||||
|
use byteorder::WriteBytesExt;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
use xz2::stream::{Action, Stream};
|
use xz2::stream::{Action, Stream};
|
||||||
use byteorder::WriteBytesExt;
|
|
||||||
input.read_u32::<LittleEndian>()?; // Compressed length
|
input.read_u32::<LittleEndian>()?; // Compressed length
|
||||||
let mut lzma_properties = [0u8; 5];
|
let mut lzma_properties = [0u8; 5];
|
||||||
input.read_exact(&mut lzma_properties)?;
|
input.read_exact(&mut lzma_properties)?;
|
||||||
|
@ -78,7 +81,10 @@ fn make_lzma_reader<'a, R: Read + 'a>(mut input: R) -> Result<Box<Read + 'a>> {
|
||||||
|
|
||||||
#[cfg(not(feature = "lzma-support"))]
|
#[cfg(not(feature = "lzma-support"))]
|
||||||
fn make_lzma_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
|
fn make_lzma_reader<'a, R: Read + 'a>(_input: R) -> Result<Box<Read + 'a>> {
|
||||||
Err(Error::new(ErrorKind::InvalidData, "Support for LZMA compressed SWFs is not enabled."))
|
Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
"Support for LZMA compressed SWFs is not enabled.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SwfRead<R: Read> {
|
pub trait SwfRead<R: Read> {
|
||||||
|
@ -143,9 +149,8 @@ pub trait SwfRead<R: Read> {
|
||||||
}
|
}
|
||||||
// TODO: There is probably a better way to do this.
|
// TODO: There is probably a better way to do this.
|
||||||
// TODO: Verify ANSI for SWF 5 and earlier.
|
// TODO: Verify ANSI for SWF 5 and earlier.
|
||||||
String::from_utf8(bytes).map_err(|_| {
|
String::from_utf8(bytes)
|
||||||
Error::new(ErrorKind::InvalidData, "Invalid string data")
|
.map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid string data"))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,12 +302,7 @@ impl<R: Read> Reader<R> {
|
||||||
let r = self.read_u8()?;
|
let r = self.read_u8()?;
|
||||||
let g = self.read_u8()?;
|
let g = self.read_u8()?;
|
||||||
let b = self.read_u8()?;
|
let b = self.read_u8()?;
|
||||||
Ok(Color {
|
Ok(Color { r, g, b, a: 255 })
|
||||||
r,
|
|
||||||
g,
|
|
||||||
b,
|
|
||||||
a: 255,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_rgba(&mut self) -> Result<Color> {
|
fn read_rgba(&mut self) -> Result<Color> {
|
||||||
|
@ -310,12 +310,7 @@ impl<R: Read> Reader<R> {
|
||||||
let g = self.read_u8()?;
|
let g = self.read_u8()?;
|
||||||
let b = self.read_u8()?;
|
let b = self.read_u8()?;
|
||||||
let a = self.read_u8()?;
|
let a = self.read_u8()?;
|
||||||
Ok(Color {
|
Ok(Color { r, g, b, a })
|
||||||
r,
|
|
||||||
g,
|
|
||||||
b,
|
|
||||||
a,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_color_transform_no_alpha(&mut self) -> Result<ColorTransform> {
|
fn read_color_transform_no_alpha(&mut self) -> Result<ColorTransform> {
|
||||||
|
@ -452,19 +447,13 @@ impl<R: Read> Reader<R> {
|
||||||
let id = tag_reader.read_u16()?;
|
let id = tag_reader.read_u16()?;
|
||||||
let mut jpeg_data = Vec::with_capacity(length - 2);
|
let mut jpeg_data = Vec::with_capacity(length - 2);
|
||||||
tag_reader.input.read_to_end(&mut jpeg_data)?;
|
tag_reader.input.read_to_end(&mut jpeg_data)?;
|
||||||
Tag::DefineBits {
|
Tag::DefineBits { id, jpeg_data }
|
||||||
id,
|
|
||||||
jpeg_data,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(TagCode::DefineBitsJpeg2) => {
|
Some(TagCode::DefineBitsJpeg2) => {
|
||||||
let id = tag_reader.read_u16()?;
|
let id = tag_reader.read_u16()?;
|
||||||
let mut jpeg_data = Vec::with_capacity(length - 2);
|
let mut jpeg_data = Vec::with_capacity(length - 2);
|
||||||
tag_reader.input.read_to_end(&mut jpeg_data)?;
|
tag_reader.input.read_to_end(&mut jpeg_data)?;
|
||||||
Tag::DefineBitsJpeg2 {
|
Tag::DefineBitsJpeg2 { id, jpeg_data }
|
||||||
id,
|
|
||||||
jpeg_data,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(TagCode::DefineBitsJpeg3) => tag_reader.read_define_bits_jpeg_3(3)?,
|
Some(TagCode::DefineBitsJpeg3) => tag_reader.read_define_bits_jpeg_3(3)?,
|
||||||
Some(TagCode::DefineBitsJpeg4) => tag_reader.read_define_bits_jpeg_3(4)?,
|
Some(TagCode::DefineBitsJpeg4) => tag_reader.read_define_bits_jpeg_3(4)?,
|
||||||
|
@ -549,9 +538,7 @@ impl<R: Read> Reader<R> {
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
};
|
};
|
||||||
Tag::EnableTelemetry {
|
Tag::EnableTelemetry { password_hash }
|
||||||
password_hash,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(TagCode::ImportAssets) => {
|
Some(TagCode::ImportAssets) => {
|
||||||
let url = tag_reader.read_c_string()?;
|
let url = tag_reader.read_c_string()?;
|
||||||
|
@ -563,10 +550,7 @@ impl<R: Read> Reader<R> {
|
||||||
name: tag_reader.read_c_string()?,
|
name: tag_reader.read_c_string()?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Tag::ImportAssets {
|
Tag::ImportAssets { url, imports }
|
||||||
url,
|
|
||||||
imports,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(TagCode::ImportAssets2) => {
|
Some(TagCode::ImportAssets2) => {
|
||||||
let url = tag_reader.read_c_string()?;
|
let url = tag_reader.read_c_string()?;
|
||||||
|
@ -580,10 +564,7 @@ impl<R: Read> Reader<R> {
|
||||||
name: tag_reader.read_c_string()?,
|
name: tag_reader.read_c_string()?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Tag::ImportAssets {
|
Tag::ImportAssets { url, imports }
|
||||||
url,
|
|
||||||
imports,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(TagCode::JpegTables) => {
|
Some(TagCode::JpegTables) => {
|
||||||
|
@ -651,10 +632,7 @@ impl<R: Read> Reader<R> {
|
||||||
let id = tag_reader.read_u16()?;
|
let id = tag_reader.read_u16()?;
|
||||||
let mut action_data = Vec::with_capacity(length);
|
let mut action_data = Vec::with_capacity(length);
|
||||||
tag_reader.input.read_to_end(&mut action_data)?;
|
tag_reader.input.read_to_end(&mut action_data)?;
|
||||||
Tag::DoInitAction {
|
Tag::DoInitAction { id, action_data }
|
||||||
id,
|
|
||||||
action_data,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(TagCode::EnableDebugger) => Tag::EnableDebugger(tag_reader.read_c_string()?),
|
Some(TagCode::EnableDebugger) => Tag::EnableDebugger(tag_reader.read_c_string()?),
|
||||||
|
@ -724,8 +702,9 @@ impl<R: Read> Reader<R> {
|
||||||
Some(TagCode::FrameLabel) => {
|
Some(TagCode::FrameLabel) => {
|
||||||
let label = tag_reader.read_c_string()?;
|
let label = tag_reader.read_c_string()?;
|
||||||
Tag::FrameLabel {
|
Tag::FrameLabel {
|
||||||
is_anchor: tag_reader.version >= 6 && length > label.len() + 1 &&
|
is_anchor: tag_reader.version >= 6
|
||||||
tag_reader.read_u8()? != 0,
|
&& length > label.len() + 1
|
||||||
|
&& tag_reader.read_u8()? != 0,
|
||||||
label,
|
label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -760,10 +739,7 @@ impl<R: Read> Reader<R> {
|
||||||
let size = length as usize;
|
let size = length as usize;
|
||||||
let mut data = vec![0; size];
|
let mut data = vec![0; size];
|
||||||
tag_reader.input.read_exact(&mut data[..])?;
|
tag_reader.input.read_exact(&mut data[..])?;
|
||||||
Tag::Unknown {
|
Tag::Unknown { tag_code, data }
|
||||||
tag_code,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -799,15 +775,13 @@ impl<R: Read> Reader<R> {
|
||||||
id,
|
id,
|
||||||
is_track_as_menu: false,
|
is_track_as_menu: false,
|
||||||
records,
|
records,
|
||||||
actions: vec![
|
actions: vec![ButtonAction {
|
||||||
ButtonAction {
|
conditions: vec![ButtonActionCondition::OverDownToOverUp]
|
||||||
conditions: vec![ButtonActionCondition::OverDownToOverUp]
|
.into_iter()
|
||||||
.into_iter()
|
.collect(),
|
||||||
.collect(),
|
key_code: None,
|
||||||
key_code: None,
|
action_data: action_data,
|
||||||
action_data: action_data,
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,10 +989,7 @@ impl<R: Read> Reader<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Tag::DefineFont(Box::new(FontV1 {
|
Ok(Tag::DefineFont(Box::new(FontV1 { id, glyphs })))
|
||||||
id,
|
|
||||||
glyphs,
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_define_font_2(&mut self, version: u8) -> Result<Tag> {
|
fn read_define_font_2(&mut self, version: u8) -> Result<Tag> {
|
||||||
|
@ -2605,12 +2576,12 @@ impl<R: Read> Reader<R> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::tag_codes::TagCode;
|
||||||
|
use crate::test_data;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use super::*;
|
|
||||||
use crate::test_data;
|
|
||||||
use crate::tag_codes::TagCode;
|
|
||||||
|
|
||||||
fn reader(data: &[u8]) -> Reader<&[u8]> {
|
fn reader(data: &[u8]) -> Reader<&[u8]> {
|
||||||
let default_version = 13;
|
let default_version = 13;
|
||||||
|
@ -2731,22 +2702,8 @@ pub mod tests {
|
||||||
.map(|_| reader.read_bit().unwrap())
|
.map(|_| reader.read_bit().unwrap())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
[
|
[
|
||||||
false,
|
false, true, false, true, false, true, false, true, false, false, true, false,
|
||||||
true,
|
false, true, false, true
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2795,13 +2752,7 @@ pub mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn read_fixed8() {
|
fn read_fixed8() {
|
||||||
let buf = [
|
let buf = [
|
||||||
0b00000000,
|
0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b10000000, 0b00000110, 0b01000000,
|
||||||
0b00000000,
|
|
||||||
0b00000000,
|
|
||||||
0b00000001,
|
|
||||||
0b10000000,
|
|
||||||
0b00000110,
|
|
||||||
0b01000000,
|
|
||||||
0b11101011,
|
0b11101011,
|
||||||
];
|
];
|
||||||
let mut reader = Reader::new(&buf[..], 1);
|
let mut reader = Reader::new(&buf[..], 1);
|
||||||
|
@ -3059,8 +3010,7 @@ pub mod tests {
|
||||||
// Failed, result doesn't match.
|
// Failed, result doesn't match.
|
||||||
panic!(
|
panic!(
|
||||||
"Incorrectly parsed tag.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
"Incorrectly parsed tag.\nRead:\n{:?}\n\nExpected:\n{:?}",
|
||||||
parsed_tag,
|
parsed_tag, expected_tag
|
||||||
expected_tag
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::useless_attribute)]
|
#![allow(clippy::useless_attribute)]
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug,PartialEq,Clone,Copy,FromPrimitive)]
|
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive)]
|
||||||
pub enum TagCode {
|
pub enum TagCode {
|
||||||
End = 0,
|
End = 0,
|
||||||
ShowFrame = 1,
|
ShowFrame = 1,
|
||||||
|
|
2889
src/test_data.rs
2889
src/test_data.rs
File diff suppressed because it is too large
Load Diff
43
src/types.rs
43
src/types.rs
|
@ -153,7 +153,6 @@ pub enum PlaceObjectAction {
|
||||||
Replace(CharacterId),
|
Replace(CharacterId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Filter {
|
pub enum Filter {
|
||||||
DropShadowFilter(Box<DropShadowFilter>),
|
DropShadowFilter(Box<DropShadowFilter>),
|
||||||
|
@ -318,9 +317,18 @@ pub enum Tag {
|
||||||
|
|
||||||
Protect(Option<String>),
|
Protect(Option<String>),
|
||||||
CsmTextSettings(CsmTextSettings),
|
CsmTextSettings(CsmTextSettings),
|
||||||
DefineBinaryData { id: CharacterId, data: Vec<u8> },
|
DefineBinaryData {
|
||||||
DefineBits { id: CharacterId, jpeg_data: Vec<u8> },
|
id: CharacterId,
|
||||||
DefineBitsJpeg2 { id: CharacterId, jpeg_data: Vec<u8> },
|
data: Vec<u8>,
|
||||||
|
},
|
||||||
|
DefineBits {
|
||||||
|
id: CharacterId,
|
||||||
|
jpeg_data: Vec<u8>,
|
||||||
|
},
|
||||||
|
DefineBitsJpeg2 {
|
||||||
|
id: CharacterId,
|
||||||
|
jpeg_data: Vec<u8>,
|
||||||
|
},
|
||||||
DefineBitsJpeg3(DefineBitsJpeg3),
|
DefineBitsJpeg3(DefineBitsJpeg3),
|
||||||
DefineBitsLossless(DefineBitsLossless),
|
DefineBitsLossless(DefineBitsLossless),
|
||||||
DefineButton(Box<Button>),
|
DefineButton(Box<Button>),
|
||||||
|
@ -362,7 +370,9 @@ pub enum Tag {
|
||||||
action_data: Vec<u8>,
|
action_data: Vec<u8>,
|
||||||
},
|
},
|
||||||
EnableDebugger(String),
|
EnableDebugger(String),
|
||||||
EnableTelemetry { password_hash: Vec<u8> },
|
EnableTelemetry {
|
||||||
|
password_hash: Vec<u8>,
|
||||||
|
},
|
||||||
Metadata(String),
|
Metadata(String),
|
||||||
ImportAssets {
|
ImportAssets {
|
||||||
url: String,
|
url: String,
|
||||||
|
@ -370,7 +380,10 @@ pub enum Tag {
|
||||||
},
|
},
|
||||||
JpegTables(Vec<u8>),
|
JpegTables(Vec<u8>),
|
||||||
SetBackgroundColor(Color),
|
SetBackgroundColor(Color),
|
||||||
SetTabIndex { depth: Depth, tab_index: u16 },
|
SetTabIndex {
|
||||||
|
depth: Depth,
|
||||||
|
tab_index: u16,
|
||||||
|
},
|
||||||
SoundStreamBlock(Vec<u8>),
|
SoundStreamBlock(Vec<u8>),
|
||||||
SoundStreamHead(Box<SoundStreamInfo>),
|
SoundStreamHead(Box<SoundStreamInfo>),
|
||||||
SoundStreamHead2(Box<SoundStreamInfo>),
|
SoundStreamHead2(Box<SoundStreamInfo>),
|
||||||
|
@ -391,13 +404,19 @@ pub enum Tag {
|
||||||
VideoFrame(VideoFrame),
|
VideoFrame(VideoFrame),
|
||||||
FileAttributes(FileAttributes),
|
FileAttributes(FileAttributes),
|
||||||
|
|
||||||
FrameLabel { label: String, is_anchor: bool },
|
FrameLabel {
|
||||||
|
label: String,
|
||||||
|
is_anchor: bool,
|
||||||
|
},
|
||||||
DefineSceneAndFrameLabelData {
|
DefineSceneAndFrameLabelData {
|
||||||
scenes: Vec<FrameLabel>,
|
scenes: Vec<FrameLabel>,
|
||||||
frame_labels: Vec<FrameLabel>,
|
frame_labels: Vec<FrameLabel>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Unknown { tag_code: u16, data: Vec<u8> },
|
Unknown {
|
||||||
|
tag_code: u16,
|
||||||
|
data: Vec<u8>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
@ -433,7 +452,6 @@ pub struct Sound {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct SoundInfo {
|
pub struct SoundInfo {
|
||||||
pub event: SoundEvent,
|
pub event: SoundEvent,
|
||||||
|
@ -443,7 +461,6 @@ pub struct SoundInfo {
|
||||||
pub envelope: Option<SoundEnvelope>,
|
pub envelope: Option<SoundEnvelope>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum SoundEvent {
|
pub enum SoundEvent {
|
||||||
Event,
|
Event,
|
||||||
|
@ -477,7 +494,10 @@ pub struct ShapeStyles {
|
||||||
pub enum ShapeRecord {
|
pub enum ShapeRecord {
|
||||||
// TODO: Twips
|
// TODO: Twips
|
||||||
StyleChange(StyleChangeData),
|
StyleChange(StyleChangeData),
|
||||||
StraightEdge { delta_x: f32, delta_y: f32 },
|
StraightEdge {
|
||||||
|
delta_x: f32,
|
||||||
|
delta_y: f32,
|
||||||
|
},
|
||||||
CurvedEdge {
|
CurvedEdge {
|
||||||
control_delta_x: f32,
|
control_delta_x: f32,
|
||||||
control_delta_y: f32,
|
control_delta_y: f32,
|
||||||
|
@ -696,7 +716,6 @@ pub struct FontV1 {
|
||||||
pub glyphs: Vec<Vec<ShapeRecord>>,
|
pub glyphs: Vec<Vec<ShapeRecord>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Font {
|
pub struct Font {
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
|
|
445
src/write.rs
445
src/write.rs
|
@ -1,11 +1,11 @@
|
||||||
#![allow(clippy::cyclomatic_complexity, clippy::float_cmp, clippy::inconsistent_digit_grouping, clippy::unreadable_literal)]
|
#![allow(clippy::cyclomatic_complexity, clippy::float_cmp, clippy::inconsistent_digit_grouping, clippy::unreadable_literal)]
|
||||||
|
|
||||||
|
use crate::tag_codes::TagCode;
|
||||||
|
use crate::types::*;
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::{Error, ErrorKind, Result, Write};
|
use std::io::{Error, ErrorKind, Result, Write};
|
||||||
use crate::tag_codes::TagCode;
|
|
||||||
use crate::types::*;
|
|
||||||
|
|
||||||
pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
|
pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
|
||||||
let signature = match swf.compression {
|
let signature = match swf.compression {
|
||||||
|
@ -53,8 +53,8 @@ pub fn write_swf<W: Write>(swf: &Swf, mut output: W) -> Result<()> {
|
||||||
|
|
||||||
#[cfg(feature = "flate2")]
|
#[cfg(feature = "flate2")]
|
||||||
fn write_zlib_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
fn write_zlib_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
||||||
use flate2::Compression;
|
|
||||||
use flate2::write::ZlibEncoder;
|
use flate2::write::ZlibEncoder;
|
||||||
|
use flate2::Compression;
|
||||||
let mut encoder = ZlibEncoder::new(&mut output, Compression::best());
|
let mut encoder = ZlibEncoder::new(&mut output, Compression::best());
|
||||||
encoder.write_all(&swf_body)
|
encoder.write_all(&swf_body)
|
||||||
}
|
}
|
||||||
|
@ -66,15 +66,18 @@ fn write_zlib_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
||||||
encoder.write_all(&swf_body)
|
encoder.write_all(&swf_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(feature = "flate2",feature = "libflate")))]
|
#[cfg(not(any(feature = "flate2", feature = "libflate")))]
|
||||||
fn write_zlib_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
|
fn write_zlib_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
|
||||||
Err(Error::new(ErrorKind::InvalidData, "Support for Zlib compressed SWFs is not enabled."))
|
Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
"Support for Zlib compressed SWFs is not enabled.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lzma-support")]
|
#[cfg(feature = "lzma-support")]
|
||||||
fn write_lzma_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
fn write_lzma_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
||||||
use xz2::write::XzEncoder;
|
|
||||||
use xz2::stream::{Action, LzmaOptions, Stream};
|
use xz2::stream::{Action, LzmaOptions, Stream};
|
||||||
|
use xz2::write::XzEncoder;
|
||||||
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?;
|
let mut stream = Stream::new_lzma_encoder(&LzmaOptions::new_preset(9)?)?;
|
||||||
let mut lzma_header = [0; 13];
|
let mut lzma_header = [0; 13];
|
||||||
stream.process(&[], &mut lzma_header, Action::Run)?;
|
stream.process(&[], &mut lzma_header, Action::Run)?;
|
||||||
|
@ -88,7 +91,10 @@ fn write_lzma_swf<W: Write>(mut output: W, swf_body: &[u8]) -> Result<()> {
|
||||||
|
|
||||||
#[cfg(not(feature = "lzma-support"))]
|
#[cfg(not(feature = "lzma-support"))]
|
||||||
fn write_lzma_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
|
fn write_lzma_swf<W: Write>(_output: W, _swf_body: &[u8]) -> Result<()> {
|
||||||
Err(Error::new(ErrorKind::InvalidData, "Support for LZMA compressed SWFs is not enabled."))
|
Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
"Support for LZMA compressed SWFs is not enabled.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SwfWrite<W: Write> {
|
pub trait SwfWrite<W: Write> {
|
||||||
|
@ -246,7 +252,6 @@ impl<W: Write> Writer<W> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn write_ubits(&mut self, num_bits: u8, n: u32) -> Result<()> {
|
fn write_ubits(&mut self, num_bits: u8, n: u32) -> Result<()> {
|
||||||
for i in 0..num_bits {
|
for i in 0..num_bits {
|
||||||
self.write_bit(n & (1 << u32::from(num_bits - i - 1)) != 0)?;
|
self.write_bit(n & (1 << u32::from(num_bits - i - 1)) != 0)?;
|
||||||
|
@ -284,10 +289,11 @@ impl<W: Write> Writer<W> {
|
||||||
rectangle.x_max,
|
rectangle.x_max,
|
||||||
rectangle.y_min,
|
rectangle.y_min,
|
||||||
rectangle.y_max,
|
rectangle.y_max,
|
||||||
].iter()
|
]
|
||||||
.map(|x| count_sbits((*x * 20f32) as i32))
|
.iter()
|
||||||
.max()
|
.map(|x| count_sbits((*x * 20f32) as i32))
|
||||||
.unwrap();
|
.max()
|
||||||
|
.unwrap();
|
||||||
self.write_ubits(5, num_bits.into())?;
|
self.write_ubits(5, num_bits.into())?;
|
||||||
self.write_sbits(num_bits, (rectangle.x_min * 20f32) as i32)?;
|
self.write_sbits(num_bits, (rectangle.x_min * 20f32) as i32)?;
|
||||||
self.write_sbits(num_bits, (rectangle.x_max * 20f32) as i32)?;
|
self.write_sbits(num_bits, (rectangle.x_max * 20f32) as i32)?;
|
||||||
|
@ -318,8 +324,9 @@ impl<W: Write> Writer<W> {
|
||||||
fn write_color_transform_no_alpha(&mut self, color_transform: &ColorTransform) -> Result<()> {
|
fn write_color_transform_no_alpha(&mut self, color_transform: &ColorTransform) -> Result<()> {
|
||||||
// TODO: Assert that alpha is 1.0?
|
// TODO: Assert that alpha is 1.0?
|
||||||
self.flush_bits()?;
|
self.flush_bits()?;
|
||||||
let has_mult = color_transform.r_multiply != 1f32 || color_transform.g_multiply != 1f32 ||
|
let has_mult = color_transform.r_multiply != 1f32
|
||||||
color_transform.b_multiply != 1f32;
|
|| color_transform.g_multiply != 1f32
|
||||||
|
|| color_transform.b_multiply != 1f32;
|
||||||
let has_add =
|
let has_add =
|
||||||
color_transform.r_add != 0 || color_transform.g_add != 0 || color_transform.b_add != 0;
|
color_transform.r_add != 0 || color_transform.g_add != 0 || color_transform.b_add != 0;
|
||||||
let multiply = [
|
let multiply = [
|
||||||
|
@ -347,7 +354,10 @@ impl<W: Write> Writer<W> {
|
||||||
if has_add {
|
if has_add {
|
||||||
num_bits = max(
|
num_bits = max(
|
||||||
num_bits,
|
num_bits,
|
||||||
add.iter().map(|n| count_sbits(i32::from(*n))).max().unwrap(),
|
add.iter()
|
||||||
|
.map(|n| count_sbits(i32::from(*n)))
|
||||||
|
.max()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.write_ubits(4, num_bits.into())?;
|
self.write_ubits(4, num_bits.into())?;
|
||||||
|
@ -366,11 +376,14 @@ impl<W: Write> Writer<W> {
|
||||||
|
|
||||||
fn write_color_transform(&mut self, color_transform: &ColorTransform) -> Result<()> {
|
fn write_color_transform(&mut self, color_transform: &ColorTransform) -> Result<()> {
|
||||||
self.flush_bits()?;
|
self.flush_bits()?;
|
||||||
let has_mult = color_transform.r_multiply != 1f32 || color_transform.g_multiply != 1f32 ||
|
let has_mult = color_transform.r_multiply != 1f32
|
||||||
color_transform.b_multiply != 1f32 ||
|
|| color_transform.g_multiply != 1f32
|
||||||
color_transform.a_multiply != 1f32;
|
|| color_transform.b_multiply != 1f32
|
||||||
let has_add = color_transform.r_add != 0 || color_transform.g_add != 0 ||
|
|| color_transform.a_multiply != 1f32;
|
||||||
color_transform.b_add != 0 || color_transform.a_add != 0;
|
let has_add = color_transform.r_add != 0
|
||||||
|
|| color_transform.g_add != 0
|
||||||
|
|| color_transform.b_add != 0
|
||||||
|
|| color_transform.a_add != 0;
|
||||||
let multiply = [
|
let multiply = [
|
||||||
color_transform.r_multiply,
|
color_transform.r_multiply,
|
||||||
color_transform.g_multiply,
|
color_transform.g_multiply,
|
||||||
|
@ -397,7 +410,10 @@ impl<W: Write> Writer<W> {
|
||||||
if has_add {
|
if has_add {
|
||||||
num_bits = max(
|
num_bits = max(
|
||||||
num_bits,
|
num_bits,
|
||||||
add.iter().map(|n| count_sbits(i32::from(*n))).max().unwrap(),
|
add.iter()
|
||||||
|
.map(|n| count_sbits(i32::from(*n)))
|
||||||
|
.max()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.write_ubits(4, num_bits.into())?;
|
self.write_ubits(4, num_bits.into())?;
|
||||||
|
@ -416,7 +432,6 @@ impl<W: Write> Writer<W> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn write_matrix(&mut self, m: &Matrix) -> Result<()> {
|
fn write_matrix(&mut self, m: &Matrix) -> Result<()> {
|
||||||
self.flush_bits()?;
|
self.flush_bits()?;
|
||||||
// Scale
|
// Scale
|
||||||
|
@ -466,8 +481,9 @@ impl<W: Write> Writer<W> {
|
||||||
Tag::ShowFrame => self.write_tag_header(TagCode::ShowFrame, 0)?,
|
Tag::ShowFrame => self.write_tag_header(TagCode::ShowFrame, 0)?,
|
||||||
|
|
||||||
Tag::ExportAssets(ref exports) => {
|
Tag::ExportAssets(ref exports) => {
|
||||||
let len = exports.iter().map(|e| e.name.len() as u32 + 1).sum::<u32>() +
|
let len = exports.iter().map(|e| e.name.len() as u32 + 1).sum::<u32>()
|
||||||
exports.len() as u32 * 2 + 2;
|
+ exports.len() as u32 * 2
|
||||||
|
+ 2;
|
||||||
self.write_tag_header(TagCode::ExportAssets, len)?;
|
self.write_tag_header(TagCode::ExportAssets, len)?;
|
||||||
self.write_u16(exports.len() as u16)?;
|
self.write_u16(exports.len() as u16)?;
|
||||||
for &ExportedAsset { id, ref name } in exports {
|
for &ExportedAsset { id, ref name } in exports {
|
||||||
|
@ -686,9 +702,10 @@ impl<W: Write> Writer<W> {
|
||||||
Tag::DefineFontInfo(ref font_info) => {
|
Tag::DefineFontInfo(ref font_info) => {
|
||||||
let use_wide_codes = self.version >= 6 || font_info.version >= 2;
|
let use_wide_codes = self.version >= 6 || font_info.version >= 2;
|
||||||
|
|
||||||
let len = font_info.name.len() +
|
let len = font_info.name.len()
|
||||||
if use_wide_codes { 2 } else { 1 } * font_info.code_table.len() +
|
+ if use_wide_codes { 2 } else { 1 } * font_info.code_table.len()
|
||||||
if font_info.version >= 2 { 1 } else { 0 } + 4;
|
+ if font_info.version >= 2 { 1 } else { 0 }
|
||||||
|
+ 4;
|
||||||
|
|
||||||
let tag_id = if font_info.version == 1 {
|
let tag_id = if font_info.version == 1 {
|
||||||
TagCode::DefineFontInfo
|
TagCode::DefineFontInfo
|
||||||
|
@ -702,14 +719,12 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_u8(font_info.name.len() as u8)?;
|
self.write_u8(font_info.name.len() as u8)?;
|
||||||
self.output.write_all(font_info.name.as_bytes())?;
|
self.output.write_all(font_info.name.as_bytes())?;
|
||||||
self.write_u8(
|
self.write_u8(
|
||||||
if font_info.is_small_text { 0b100000 } else { 0 } | if font_info.is_ansi {
|
if font_info.is_small_text { 0b100000 } else { 0 }
|
||||||
0b10000
|
| if font_info.is_ansi { 0b10000 } else { 0 }
|
||||||
} else {
|
| if font_info.is_shift_jis { 0b1000 } else { 0 }
|
||||||
0
|
| if font_info.is_italic { 0b100 } else { 0 }
|
||||||
} | if font_info.is_shift_jis { 0b1000 } else { 0 } |
|
| if font_info.is_bold { 0b10 } else { 0 }
|
||||||
if font_info.is_italic { 0b100 } else { 0 } |
|
| if use_wide_codes { 0b1 } else { 0 },
|
||||||
if font_info.is_bold { 0b10 } else { 0 } |
|
|
||||||
if use_wide_codes { 0b1 } else { 0 },
|
|
||||||
)?;
|
)?;
|
||||||
// TODO(Herschel): Assert language is unknown for v1.
|
// TODO(Herschel): Assert language is unknown for v1.
|
||||||
if font_info.version >= 2 {
|
if font_info.version >= 2 {
|
||||||
|
@ -793,21 +808,25 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_c_string(password_md5)?;
|
self.write_c_string(password_md5)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag::EnableTelemetry { ref password_hash } => if !password_hash.is_empty() {
|
Tag::EnableTelemetry { ref password_hash } => {
|
||||||
self.write_tag_header(TagCode::EnableTelemetry, 34)?;
|
if !password_hash.is_empty() {
|
||||||
self.write_u16(0)?;
|
self.write_tag_header(TagCode::EnableTelemetry, 34)?;
|
||||||
self.output.write_all(&password_hash[0..32])?;
|
self.write_u16(0)?;
|
||||||
} else {
|
self.output.write_all(&password_hash[0..32])?;
|
||||||
self.write_tag_header(TagCode::EnableTelemetry, 2)?;
|
} else {
|
||||||
self.write_u16(0)?;
|
self.write_tag_header(TagCode::EnableTelemetry, 2)?;
|
||||||
},
|
self.write_u16(0)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Tag::ImportAssets {
|
Tag::ImportAssets {
|
||||||
ref url,
|
ref url,
|
||||||
ref imports,
|
ref imports,
|
||||||
} => {
|
} => {
|
||||||
let len = imports.iter().map(|e| e.name.len() as u32 + 3).sum::<u32>() +
|
let len = imports.iter().map(|e| e.name.len() as u32 + 3).sum::<u32>()
|
||||||
url.len() as u32 + 1 + 2;
|
+ url.len() as u32
|
||||||
|
+ 1
|
||||||
|
+ 2;
|
||||||
// SWF v8 and later use ImportAssets2 tag.
|
// SWF v8 and later use ImportAssets2 tag.
|
||||||
if self.version >= 8 {
|
if self.version >= 8 {
|
||||||
self.write_tag_header(TagCode::ImportAssets2, len + 2)?;
|
self.write_tag_header(TagCode::ImportAssets2, len + 2)?;
|
||||||
|
@ -896,13 +915,15 @@ impl<W: Write> Writer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag::StartSound { id, ref sound_info } => {
|
Tag::StartSound { id, ref sound_info } => {
|
||||||
let length = 3 + if sound_info.in_sample.is_some() { 4 } else { 0 } +
|
let length = 3
|
||||||
if sound_info.out_sample.is_some() {
|
+ if sound_info.in_sample.is_some() { 4 } else { 0 }
|
||||||
|
+ if sound_info.out_sample.is_some() {
|
||||||
4
|
4
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} + if sound_info.num_loops > 1 { 2 } else { 0 } +
|
}
|
||||||
if let Some(ref e) = sound_info.envelope {
|
+ if sound_info.num_loops > 1 { 2 } else { 0 }
|
||||||
|
+ if let Some(ref e) = sound_info.envelope {
|
||||||
e.len() as u32 * 8 + 1
|
e.len() as u32 * 8 + 1
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
@ -916,16 +937,16 @@ impl<W: Write> Writer<W> {
|
||||||
ref class_name,
|
ref class_name,
|
||||||
ref sound_info,
|
ref sound_info,
|
||||||
} => {
|
} => {
|
||||||
let length = class_name.len() as u32 + 2 + if sound_info.in_sample.is_some() {
|
let length = class_name.len() as u32
|
||||||
4
|
+ 2
|
||||||
} else {
|
+ if sound_info.in_sample.is_some() { 4 } else { 0 }
|
||||||
0
|
+ if sound_info.out_sample.is_some() {
|
||||||
} + if sound_info.out_sample.is_some() {
|
4
|
||||||
4
|
} else {
|
||||||
} else {
|
0
|
||||||
0
|
}
|
||||||
} + if sound_info.num_loops > 1 { 2 } else { 0 } +
|
+ if sound_info.num_loops > 1 { 2 } else { 0 }
|
||||||
if let Some(ref e) = sound_info.envelope {
|
+ if let Some(ref e) = sound_info.envelope {
|
||||||
e.len() as u32 * 8 + 1
|
e.len() as u32 * 8 + 1
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
@ -939,7 +960,8 @@ impl<W: Write> Writer<W> {
|
||||||
let len = symbols
|
let len = symbols
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| e.class_name.len() as u32 + 3)
|
.map(|e| e.class_name.len() as u32 + 3)
|
||||||
.sum::<u32>() + 2;
|
.sum::<u32>()
|
||||||
|
+ 2;
|
||||||
self.write_tag_header(TagCode::SymbolClass, len)?;
|
self.write_tag_header(TagCode::SymbolClass, len)?;
|
||||||
self.write_u16(symbols.len() as u16)?;
|
self.write_u16(symbols.len() as u16)?;
|
||||||
for &SymbolClassLink { id, ref class_name } in symbols {
|
for &SymbolClassLink { id, ref class_name } in symbols {
|
||||||
|
@ -1012,7 +1034,7 @@ impl<W: Write> Writer<W> {
|
||||||
writer.write_button_record(record, 1)?;
|
writer.write_button_record(record, 1)?;
|
||||||
}
|
}
|
||||||
writer.write_u8(0)?; // End button records
|
writer.write_u8(0)?; // End button records
|
||||||
// TODO: Assert we have some action.
|
// TODO: Assert we have some action.
|
||||||
writer.output.write_all(&button.actions[0].action_data)?;
|
writer.output.write_all(&button.actions[0].action_data)?;
|
||||||
}
|
}
|
||||||
self.write_tag_header(TagCode::DefineButton, buf.len() as u32)?;
|
self.write_tag_header(TagCode::DefineButton, buf.len() as u32)?;
|
||||||
|
@ -1055,63 +1077,56 @@ impl<W: Write> Writer<W> {
|
||||||
0b1000_0000
|
0b1000_0000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} |
|
} | if action
|
||||||
if action
|
.conditions
|
||||||
.conditions
|
.contains(&ButtonActionCondition::OutDownToIdle)
|
||||||
.contains(&ButtonActionCondition::OutDownToIdle)
|
{
|
||||||
{
|
0b100_0000
|
||||||
0b100_0000
|
} else {
|
||||||
} else {
|
0
|
||||||
0
|
} | if action
|
||||||
} |
|
.conditions
|
||||||
if action
|
.contains(&ButtonActionCondition::OutDownToOverDown)
|
||||||
.conditions
|
{
|
||||||
.contains(&ButtonActionCondition::OutDownToOverDown)
|
0b10_0000
|
||||||
{
|
} else {
|
||||||
0b10_0000
|
0
|
||||||
} else {
|
} | if action
|
||||||
0
|
.conditions
|
||||||
} |
|
.contains(&ButtonActionCondition::OverDownToOutDown)
|
||||||
if action
|
{
|
||||||
.conditions
|
0b1_0000
|
||||||
.contains(&ButtonActionCondition::OverDownToOutDown)
|
} else {
|
||||||
{
|
0
|
||||||
0b1_0000
|
} | if action
|
||||||
} else {
|
.conditions
|
||||||
0
|
.contains(&ButtonActionCondition::OverDownToOverUp)
|
||||||
} |
|
{
|
||||||
if action
|
0b1000
|
||||||
.conditions
|
} else {
|
||||||
.contains(&ButtonActionCondition::OverDownToOverUp)
|
0
|
||||||
{
|
} | if action
|
||||||
0b1000
|
.conditions
|
||||||
} else {
|
.contains(&ButtonActionCondition::OverUpToOverDown)
|
||||||
0
|
{
|
||||||
} |
|
0b100
|
||||||
if action
|
} else {
|
||||||
.conditions
|
0
|
||||||
.contains(&ButtonActionCondition::OverUpToOverDown)
|
} | if action
|
||||||
{
|
.conditions
|
||||||
0b100
|
.contains(&ButtonActionCondition::OverUpToIdle)
|
||||||
} else {
|
{
|
||||||
0
|
0b10
|
||||||
} |
|
} else {
|
||||||
if action
|
0
|
||||||
.conditions
|
} | if action
|
||||||
.contains(&ButtonActionCondition::OverUpToIdle)
|
.conditions
|
||||||
{
|
.contains(&ButtonActionCondition::IdleToOverUp)
|
||||||
0b10
|
{
|
||||||
} else {
|
0b1
|
||||||
0
|
} else {
|
||||||
} |
|
0
|
||||||
if action
|
},
|
||||||
.conditions
|
|
||||||
.contains(&ButtonActionCondition::IdleToOverUp)
|
|
||||||
{
|
|
||||||
0b1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
let mut flags = if action
|
let mut flags = if action
|
||||||
.conditions
|
.conditions
|
||||||
|
@ -1136,8 +1151,8 @@ impl<W: Write> Writer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_define_morph_shape(&mut self, data: &DefineMorphShape) -> Result<()> {
|
fn write_define_morph_shape(&mut self, data: &DefineMorphShape) -> Result<()> {
|
||||||
if data.start.fill_styles.len() != data.end.fill_styles.len() ||
|
if data.start.fill_styles.len() != data.end.fill_styles.len()
|
||||||
data.start.line_styles.len() != data.end.line_styles.len()
|
|| data.start.line_styles.len() != data.end.line_styles.len()
|
||||||
{
|
{
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidData,
|
ErrorKind::InvalidData,
|
||||||
|
@ -1163,7 +1178,8 @@ impl<W: Write> Writer<W> {
|
||||||
} else {
|
} else {
|
||||||
writer.write_u8(num_fill_styles as u8)?;
|
writer.write_u8(num_fill_styles as u8)?;
|
||||||
}
|
}
|
||||||
for (start, end) in data.start
|
for (start, end) in data
|
||||||
|
.start
|
||||||
.fill_styles
|
.fill_styles
|
||||||
.iter()
|
.iter()
|
||||||
.zip(data.end.fill_styles.iter())
|
.zip(data.end.fill_styles.iter())
|
||||||
|
@ -1177,7 +1193,8 @@ impl<W: Write> Writer<W> {
|
||||||
} else {
|
} else {
|
||||||
writer.write_u8(num_line_styles as u8)?;
|
writer.write_u8(num_line_styles as u8)?;
|
||||||
}
|
}
|
||||||
for (start, end) in data.start
|
for (start, end) in data
|
||||||
|
.start
|
||||||
.line_styles
|
.line_styles
|
||||||
.iter()
|
.iter()
|
||||||
.zip(data.end.line_styles.iter())
|
.zip(data.end.line_styles.iter())
|
||||||
|
@ -1309,8 +1326,8 @@ impl<W: Write> Writer<W> {
|
||||||
is_smoothed: end_is_smoothed,
|
is_smoothed: end_is_smoothed,
|
||||||
is_repeating: end_is_repeating,
|
is_repeating: end_is_repeating,
|
||||||
},
|
},
|
||||||
) if id == end_id && is_smoothed == end_is_smoothed ||
|
) if id == end_id && is_smoothed == end_is_smoothed
|
||||||
is_repeating == end_is_repeating =>
|
|| is_repeating == end_is_repeating =>
|
||||||
{
|
{
|
||||||
let fill_style_type = match (is_smoothed, is_repeating) {
|
let fill_style_type = match (is_smoothed, is_repeating) {
|
||||||
(true, true) => 0x40,
|
(true, true) => 0x40,
|
||||||
|
@ -1365,11 +1382,13 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_rgba(&start.color)?;
|
self.write_rgba(&start.color)?;
|
||||||
self.write_rgba(&end.color)?;
|
self.write_rgba(&end.color)?;
|
||||||
} else {
|
} else {
|
||||||
if start.start_cap != end.start_cap || start.join_style != end.join_style ||
|
if start.start_cap != end.start_cap
|
||||||
start.allow_scale_x != end.allow_scale_x ||
|
|| start.join_style != end.join_style
|
||||||
start.allow_scale_y != end.allow_scale_y ||
|
|| start.allow_scale_x != end.allow_scale_x
|
||||||
start.is_pixel_hinted != end.is_pixel_hinted ||
|
|| start.allow_scale_y != end.allow_scale_y
|
||||||
start.allow_close != end.allow_close || start.end_cap != end.end_cap
|
|| start.is_pixel_hinted != end.is_pixel_hinted
|
||||||
|
|| start.allow_close != end.allow_close
|
||||||
|
|| start.end_cap != end.end_cap
|
||||||
{
|
{
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidData,
|
ErrorKind::InvalidData,
|
||||||
|
@ -1664,10 +1683,11 @@ impl<W: Write> Writer<W> {
|
||||||
control_twips_y,
|
control_twips_y,
|
||||||
anchor_twips_x,
|
anchor_twips_x,
|
||||||
anchor_twips_y,
|
anchor_twips_y,
|
||||||
].iter()
|
]
|
||||||
.map(|x| count_sbits(*x))
|
.iter()
|
||||||
.max()
|
.map(|x| count_sbits(*x))
|
||||||
.unwrap();
|
.max()
|
||||||
|
.unwrap();
|
||||||
self.write_ubits(4, u32::from(num_bits) - 2)?;
|
self.write_ubits(4, u32::from(num_bits) - 2)?;
|
||||||
self.write_sbits(num_bits, control_twips_x)?;
|
self.write_sbits(num_bits, control_twips_x)?;
|
||||||
self.write_sbits(num_bits, control_twips_y)?;
|
self.write_sbits(num_bits, control_twips_y)?;
|
||||||
|
@ -1928,24 +1948,27 @@ impl<W: Write> Writer<W> {
|
||||||
0b10_0000
|
0b10_0000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if place_object.is_image { 0b1_0000 } else { 0 } |
|
} | if place_object.is_image { 0b1_0000 } else { 0 }
|
||||||
if place_object.class_name.is_some() {
|
| if place_object.class_name.is_some() {
|
||||||
0b1000
|
0b1000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if place_object.is_bitmap_cached {
|
}
|
||||||
0b100
|
| if place_object.is_bitmap_cached {
|
||||||
} else {
|
0b100
|
||||||
0
|
} else {
|
||||||
} | if place_object.blend_mode != BlendMode::Normal {
|
0
|
||||||
0b10
|
}
|
||||||
} else {
|
| if place_object.blend_mode != BlendMode::Normal {
|
||||||
0
|
0b10
|
||||||
} | if !place_object.filters.is_empty() {
|
} else {
|
||||||
0b1
|
0
|
||||||
} else {
|
}
|
||||||
0
|
| if !place_object.filters.is_empty() {
|
||||||
},
|
0b1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
writer.write_i16(place_object.depth)?;
|
writer.write_i16(place_object.depth)?;
|
||||||
|
@ -1957,8 +1980,8 @@ impl<W: Write> Writer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match place_object.action {
|
match place_object.action {
|
||||||
PlaceObjectAction::Place(character_id) |
|
PlaceObjectAction::Place(character_id)
|
||||||
PlaceObjectAction::Replace(character_id) => writer.write_u16(character_id)?,
|
| PlaceObjectAction::Replace(character_id) => writer.write_u16(character_id)?,
|
||||||
PlaceObjectAction::Modify => (),
|
PlaceObjectAction::Modify => (),
|
||||||
}
|
}
|
||||||
if let Some(ref matrix) = place_object.matrix {
|
if let Some(ref matrix) = place_object.matrix {
|
||||||
|
@ -2113,11 +2136,8 @@ impl<W: Write> Writer<W> {
|
||||||
}
|
}
|
||||||
self.write_rgba(&convolve.default_color)?;
|
self.write_rgba(&convolve.default_color)?;
|
||||||
self.write_u8(
|
self.write_u8(
|
||||||
if convolve.is_clamped { 0b10 } else { 0 } | if convolve.is_preserve_alpha {
|
if convolve.is_clamped { 0b10 } else { 0 }
|
||||||
0b1
|
| if convolve.is_preserve_alpha { 0b1 } else { 0 },
|
||||||
} else {
|
|
||||||
0
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2279,8 +2299,8 @@ impl<W: Write> Writer<W> {
|
||||||
0b10
|
0b10
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if sound_info.num_loops > 1 { 0b100 } else { 0 } |
|
} | if sound_info.num_loops > 1 { 0b100 } else { 0 }
|
||||||
if sound_info.envelope.is_some() {
|
| if sound_info.envelope.is_some() {
|
||||||
0b1000
|
0b1000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
@ -2346,20 +2366,14 @@ impl<W: Write> Writer<W> {
|
||||||
let mut writer = Writer::new(&mut buf, self.version);
|
let mut writer = Writer::new(&mut buf, self.version);
|
||||||
writer.write_character_id(font.id)?;
|
writer.write_character_id(font.id)?;
|
||||||
writer.write_u8(
|
writer.write_u8(
|
||||||
if font.layout.is_some() { 0b10000000 } else { 0 } | if font.is_shift_jis {
|
if font.layout.is_some() { 0b10000000 } else { 0 }
|
||||||
0b1000000
|
| if font.is_shift_jis { 0b1000000 } else { 0 }
|
||||||
} else {
|
| if font.is_small_text { 0b100000 } else { 0 }
|
||||||
0
|
| if font.is_ansi { 0b10000 } else { 0 }
|
||||||
} | if font.is_small_text { 0b100000 } else { 0 } |
|
| if has_wide_offsets { 0b1000 } else { 0 }
|
||||||
if font.is_ansi { 0b10000 } else { 0 } | if has_wide_offsets {
|
| if has_wide_codes { 0b100 } else { 0 }
|
||||||
0b1000
|
| if font.is_italic { 0b10 } else { 0 }
|
||||||
} else {
|
| if font.is_bold { 0b1 } else { 0 },
|
||||||
0
|
|
||||||
} | if has_wide_codes { 0b100 } else { 0 } | if font.is_italic {
|
|
||||||
0b10
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
} | if font.is_bold { 0b1 } else { 0 },
|
|
||||||
)?;
|
)?;
|
||||||
writer.write_language(font.language)?;
|
writer.write_language(font.language)?;
|
||||||
writer.write_u8(font.name.len() as u8)?;
|
writer.write_u8(font.name.len() as u8)?;
|
||||||
|
@ -2434,8 +2448,9 @@ impl<W: Write> Writer<W> {
|
||||||
self.write_tag_header(TagCode::DefineFont4, tag_len as u32)?;
|
self.write_tag_header(TagCode::DefineFont4, tag_len as u32)?;
|
||||||
self.write_character_id(font.id)?;
|
self.write_character_id(font.id)?;
|
||||||
self.write_u8(
|
self.write_u8(
|
||||||
if font.data.is_some() { 0b100 } else { 0 } | if font.is_italic { 0b10 } else { 0 } |
|
if font.data.is_some() { 0b100 } else { 0 }
|
||||||
if font.is_bold { 0b1 } else { 0 },
|
| if font.is_italic { 0b10 } else { 0 }
|
||||||
|
| if font.is_bold { 0b1 } else { 0 },
|
||||||
)?;
|
)?;
|
||||||
self.write_c_string(&font.name)?;
|
self.write_c_string(&font.name)?;
|
||||||
if let Some(ref data) = font.data {
|
if let Some(ref data) = font.data {
|
||||||
|
@ -2467,12 +2482,14 @@ impl<W: Write> Writer<W> {
|
||||||
writer.write_character_id(text.id)?;
|
writer.write_character_id(text.id)?;
|
||||||
writer.write_rectangle(&text.bounds)?;
|
writer.write_rectangle(&text.bounds)?;
|
||||||
writer.write_matrix(&text.matrix)?;
|
writer.write_matrix(&text.matrix)?;
|
||||||
let num_glyph_bits = text.records
|
let num_glyph_bits = text
|
||||||
|
.records
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|r| r.glyphs.iter().map(|g| count_ubits(g.index)))
|
.flat_map(|r| r.glyphs.iter().map(|g| count_ubits(g.index)))
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let num_advance_bits = text.records
|
let num_advance_bits = text
|
||||||
|
.records
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|r| r.glyphs.iter().map(|g| count_sbits(g.advance)))
|
.flat_map(|r| r.glyphs.iter().map(|g| count_sbits(g.advance)))
|
||||||
.max()
|
.max()
|
||||||
|
@ -2481,10 +2498,11 @@ impl<W: Write> Writer<W> {
|
||||||
writer.write_u8(num_advance_bits)?;
|
writer.write_u8(num_advance_bits)?;
|
||||||
|
|
||||||
for record in &text.records {
|
for record in &text.records {
|
||||||
let flags = 0b10000000 | if record.font_id.is_some() { 0b1000 } else { 0 } |
|
let flags = 0b10000000
|
||||||
if record.color.is_some() { 0b100 } else { 0 } |
|
| if record.font_id.is_some() { 0b1000 } else { 0 }
|
||||||
if record.y_offset.is_some() { 0b10 } else { 0 } |
|
| if record.color.is_some() { 0b100 } else { 0 }
|
||||||
if record.x_offset.is_some() { 0b1 } else { 0 };
|
| if record.y_offset.is_some() { 0b10 } else { 0 }
|
||||||
|
| if record.x_offset.is_some() { 0b1 } else { 0 };
|
||||||
writer.write_u8(flags)?;
|
writer.write_u8(flags)?;
|
||||||
if let Some(id) = record.font_id {
|
if let Some(id) = record.font_id {
|
||||||
writer.write_character_id(id)?;
|
writer.write_character_id(id)?;
|
||||||
|
@ -2524,30 +2542,32 @@ impl<W: Write> Writer<W> {
|
||||||
0b10000000
|
0b10000000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if edit_text.is_word_wrap { 0b1000000 } else { 0 } |
|
} | if edit_text.is_word_wrap { 0b1000000 } else { 0 }
|
||||||
if edit_text.is_multiline { 0b100000 } else { 0 } |
|
| if edit_text.is_multiline { 0b100000 } else { 0 }
|
||||||
if edit_text.is_password { 0b10000 } else { 0 } |
|
| if edit_text.is_password { 0b10000 } else { 0 }
|
||||||
if edit_text.is_read_only { 0b1000 } else { 0 } |
|
| if edit_text.is_read_only { 0b1000 } else { 0 }
|
||||||
if edit_text.color.is_some() { 0b100 } else { 0 } |
|
| if edit_text.color.is_some() { 0b100 } else { 0 }
|
||||||
if edit_text.max_length.is_some() {
|
| if edit_text.max_length.is_some() {
|
||||||
0b10
|
0b10
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if edit_text.font_id.is_some() { 0b1 } else { 0 };
|
}
|
||||||
|
| if edit_text.font_id.is_some() { 0b1 } else { 0 };
|
||||||
let flags2 = if edit_text.font_class_name.is_some() {
|
let flags2 = if edit_text.font_class_name.is_some() {
|
||||||
0b10000000
|
0b10000000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if edit_text.is_auto_size { 0b1000000 } else { 0 } |
|
} | if edit_text.is_auto_size { 0b1000000 } else { 0 }
|
||||||
if edit_text.layout.is_some() {
|
| if edit_text.layout.is_some() {
|
||||||
0b100000
|
0b100000
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
} | if !edit_text.is_selectable { 0b10000 } else { 0 } |
|
}
|
||||||
if edit_text.has_border { 0b1000 } else { 0 } |
|
| if !edit_text.is_selectable { 0b10000 } else { 0 }
|
||||||
if edit_text.was_static { 0b100 } else { 0 } |
|
| if edit_text.has_border { 0b1000 } else { 0 }
|
||||||
if edit_text.is_html { 0b10 } else { 0 } |
|
| if edit_text.was_static { 0b100 } else { 0 }
|
||||||
if !edit_text.is_device_font { 0b1 } else { 0 };
|
| if edit_text.is_html { 0b10 } else { 0 }
|
||||||
|
| if !edit_text.is_device_font { 0b1 } else { 0 };
|
||||||
|
|
||||||
writer.write_u8(flags)?;
|
writer.write_u8(flags)?;
|
||||||
writer.write_u8(flags2)?;
|
writer.write_u8(flags2)?;
|
||||||
|
@ -2677,10 +2697,10 @@ fn count_fbits(n: f32) -> u8 {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use super::Writer;
|
use super::Writer;
|
||||||
use std::io::Result;
|
use super::*;
|
||||||
use crate::test_data;
|
use crate::test_data;
|
||||||
|
use std::io::Result;
|
||||||
|
|
||||||
fn new_swf() -> Swf {
|
fn new_swf() -> Swf {
|
||||||
Swf {
|
Swf {
|
||||||
|
@ -2735,13 +2755,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
buf,
|
buf,
|
||||||
[
|
[
|
||||||
0b00000000,
|
0b00000000, 0b00000000, 0b00000000, 0b00000001, 0b10000000, 0b00000110, 0b01000000,
|
||||||
0b00000000,
|
|
||||||
0b00000000,
|
|
||||||
0b00000001,
|
|
||||||
0b10000000,
|
|
||||||
0b00000110,
|
|
||||||
0b01000000,
|
|
||||||
0b11101011
|
0b11101011
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -2780,22 +2794,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn write_bit() {
|
fn write_bit() {
|
||||||
let bits = [
|
let bits = [
|
||||||
false,
|
false, true, false, true, false, true, false, true, false, false, true, false, false,
|
||||||
true,
|
true, false, true,
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
];
|
];
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
{
|
{
|
||||||
|
@ -2900,10 +2900,7 @@ mod tests {
|
||||||
let mut writer = Writer::new(&mut buf, 1);
|
let mut writer = Writer::new(&mut buf, 1);
|
||||||
writer.write_c_string("😀😂!🐼").unwrap();
|
writer.write_c_string("😀😂!🐼").unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(buf, "😀😂!🐼\0".bytes().collect::<Vec<_>>());
|
||||||
buf,
|
|
||||||
"😀😂!🐼\0".bytes().collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2999,9 +2996,7 @@ mod tests {
|
||||||
if written_tag_bytes != expected_tag_bytes {
|
if written_tag_bytes != expected_tag_bytes {
|
||||||
panic!(
|
panic!(
|
||||||
"Error reading tag.\nTag:\n{:?}\n\nWrote:\n{:?}\n\nExpected:\n{:?}",
|
"Error reading tag.\nTag:\n{:?}\n\nWrote:\n{:?}\n\nExpected:\n{:?}",
|
||||||
tag,
|
tag, written_tag_bytes, expected_tag_bytes
|
||||||
written_tag_bytes,
|
|
||||||
expected_tag_bytes
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue