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