swf: Use EnumSet for ClipEventFlag

This commit is contained in:
Mike Welsh 2019-12-01 11:05:25 -08:00
parent 174426856f
commit da13b36e47
6 changed files with 83 additions and 74 deletions

1
Cargo.lock generated
View File

@ -1842,6 +1842,7 @@ name = "swf"
version = "0.1.2"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"enumset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -11,6 +11,7 @@ description = "Read and write the Adobe Flash SWF file format."
[dependencies]
byteorder = "1.0"
enumset = "0.4.2"
num-derive = "0.3"
num-traits = "0.2"
libflate = {version = "0.1", optional = true}

View File

@ -7,6 +7,7 @@
use crate::error::{Error, Result};
use crate::types::*;
use byteorder::{LittleEndian, ReadBytesExt};
use enumset::EnumSet;
use std::collections::HashSet;
use std::convert::TryInto;
use std::io::{self, Read};
@ -2234,7 +2235,7 @@ impl<R: Read> Reader<R> {
Ok(None)
} else {
let mut length = self.read_u32()?;
let key_code = if events.contains(&ClipEvent::KeyPress) {
let key_code = if events.contains(ClipEventFlag::KeyPress) {
// ActionData length includes the 1 byte key code.
length -= 1;
Some(self.read_u8()?)
@ -2253,32 +2254,32 @@ impl<R: Read> Reader<R> {
}
}
fn read_clip_event_flags(&mut self) -> Result<HashSet<ClipEvent>> {
fn read_clip_event_flags(&mut self) -> Result<EnumSet<ClipEventFlag>> {
// TODO: Switch to a bitset.
let mut event_list = HashSet::with_capacity(32);
let mut event_list = EnumSet::new();
if self.read_bit()? {
event_list.insert(ClipEvent::KeyUp);
event_list.insert(ClipEventFlag::KeyUp);
}
if self.read_bit()? {
event_list.insert(ClipEvent::KeyDown);
event_list.insert(ClipEventFlag::KeyDown);
}
if self.read_bit()? {
event_list.insert(ClipEvent::MouseUp);
event_list.insert(ClipEventFlag::MouseUp);
}
if self.read_bit()? {
event_list.insert(ClipEvent::MouseDown);
event_list.insert(ClipEventFlag::MouseDown);
}
if self.read_bit()? {
event_list.insert(ClipEvent::MouseMove);
event_list.insert(ClipEventFlag::MouseMove);
}
if self.read_bit()? {
event_list.insert(ClipEvent::Unload);
event_list.insert(ClipEventFlag::Unload);
}
if self.read_bit()? {
event_list.insert(ClipEvent::EnterFrame);
event_list.insert(ClipEventFlag::EnterFrame);
}
if self.read_bit()? {
event_list.insert(ClipEvent::Load);
event_list.insert(ClipEventFlag::Load);
}
if self.version < 6 {
// SWF19 pp. 48-50: For SWFv5, the ClipEventFlags only had 2 bytes of flags,
@ -2287,41 +2288,41 @@ impl<R: Read> Reader<R> {
self.read_u8()?;
} else {
if self.read_bit()? {
event_list.insert(ClipEvent::DragOver);
event_list.insert(ClipEventFlag::DragOver);
}
if self.read_bit()? {
event_list.insert(ClipEvent::RollOut);
event_list.insert(ClipEventFlag::RollOut);
}
if self.read_bit()? {
event_list.insert(ClipEvent::RollOver);
event_list.insert(ClipEventFlag::RollOver);
}
if self.read_bit()? {
event_list.insert(ClipEvent::ReleaseOutside);
event_list.insert(ClipEventFlag::ReleaseOutside);
}
if self.read_bit()? {
event_list.insert(ClipEvent::Release);
event_list.insert(ClipEventFlag::Release);
}
if self.read_bit()? {
event_list.insert(ClipEvent::Press);
event_list.insert(ClipEventFlag::Press);
}
if self.read_bit()? {
event_list.insert(ClipEvent::Initialize);
event_list.insert(ClipEventFlag::Initialize);
}
if self.read_bit()? {
event_list.insert(ClipEvent::Data);
event_list.insert(ClipEventFlag::Data);
}
if self.version < 6 {
self.read_u16()?;
} else {
self.read_ubits(5)?;
if self.read_bit()? && self.version >= 7 {
event_list.insert(ClipEvent::Construct);
event_list.insert(ClipEventFlag::Construct);
}
if self.read_bit()? {
event_list.insert(ClipEvent::KeyPress);
event_list.insert(ClipEventFlag::KeyPress);
}
if self.read_bit()? {
event_list.insert(ClipEvent::DragOut);
event_list.insert(ClipEventFlag::DragOut);
}
self.read_u8()?;
}

View File

@ -2123,7 +2123,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
background_color: None,
blend_mode: BlendMode::Normal,
clip_actions: vec![ClipAction {
events: vec![ClipEvent::EnterFrame].into_iter().collect(),
events: ClipEventFlag::EnterFrame.into(),
key_code: None,
action_data: vec![150, 6, 0, 0, 99, 108, 105, 112, 0, 38, 0],
}],
@ -2154,19 +2154,17 @@ pub fn tag_tests() -> Vec<TagTestData> {
blend_mode: BlendMode::Normal,
clip_actions: vec![
ClipAction {
events: vec![ClipEvent::Press, ClipEvent::Release]
.into_iter()
.collect(),
events: ClipEventFlag::Press | ClipEventFlag::Release,
key_code: None,
action_data: vec![150, 3, 0, 0, 65, 0, 38, 0],
},
ClipAction {
events: vec![ClipEvent::KeyPress].into_iter().collect(),
events: ClipEventFlag::KeyPress.into(),
key_code: Some(99),
action_data: vec![150, 3, 0, 0, 66, 0, 38, 0],
},
ClipAction {
events: vec![ClipEvent::EnterFrame].into_iter().collect(),
events: ClipEventFlag::EnterFrame.into(),
key_code: None,
action_data: vec![150, 3, 0, 0, 67, 0, 38, 0],
},
@ -2326,14 +2324,12 @@ pub fn tag_tests() -> Vec<TagTestData> {
blend_mode: BlendMode::Difference,
clip_actions: vec![
ClipAction {
events: vec![ClipEvent::ReleaseOutside, ClipEvent::RollOver]
.into_iter()
.collect(),
events: ClipEventFlag::ReleaseOutside | ClipEventFlag::RollOver,
key_code: None,
action_data: vec![0],
},
ClipAction {
events: vec![ClipEvent::Data].into_iter().collect(),
events: ClipEventFlag::Data.into(),
key_code: None,
action_data: vec![150, 3, 0, 0, 66, 0, 38, 0],
},

View File

@ -3,6 +3,7 @@
//! These structures are documented in the Adobe SWF File Foramt Specification
//! version 19 (henceforth SWF19):
//! https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf
use enumset::{EnumSet, EnumSetType};
use std::collections::HashSet;
/// A complete header and tags in the SWF file.
@ -412,37 +413,46 @@ pub enum BlendMode {
HardLight,
}
#[derive(Debug, PartialEq, Eq, Clone)]
/// An clip action (a.k.a. clip event) placed on a movieclip instance.
/// Created in the Flash IDE using `onClipEvent` or `on` blocks.
///
/// [SWF19 pp.37-38 ClipActionRecord](https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf#page=37)
#[derive(Debug, Clone, PartialEq)]
pub struct ClipAction {
pub events: HashSet<ClipEvent>,
pub key_code: Option<u8>,
pub events: EnumSet<ClipEventFlag>,
pub key_code: Option<KeyCode>,
pub action_data: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum ClipEvent {
/// An event that can be attached to a movieclip instance using
/// an `onClipEvent` or `on` block.
///
/// [SWF19 pp.48-50 ClipEvent](https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf#page=38)
#[derive(Debug, EnumSetType)]
pub enum ClipEventFlag {
Construct,
Data,
DragOut,
DragOver,
EnterFrame,
Initialize,
KeyUp,
KeyDown,
KeyPress,
Load,
MouseUp,
MouseDown,
MouseMove,
Unload,
EnterFrame,
Load,
DragOver,
Press,
RollOut,
RollOver,
ReleaseOutside,
Release,
Press,
Initialize,
Data,
Construct,
KeyPress,
DragOut,
ReleaseOutside,
Unload,
}
pub type ClipEventFlags = HashSet<ClipEvent>;
/// A key code used in `ButtonAction` and `ClipAction` key press events.
pub type KeyCode = u8;
/// Represents a tag in an SWF file.
///

View File

@ -9,8 +9,8 @@ use crate::error::{Error, Result};
use crate::tag_code::TagCode;
use crate::types::*;
use byteorder::{LittleEndian, WriteBytesExt};
use enumset::EnumSet;
use std::cmp::max;
use std::collections::HashSet;
use std::io::{self, Write};
/// Writes an SWF file to an output stream.
@ -2195,14 +2195,14 @@ impl<W: Write> Writer<W> {
fn write_clip_actions(&mut self, clip_actions: &[ClipAction]) -> Result<()> {
self.write_u16(0)?; // Reserved
{
let mut all_events = HashSet::with_capacity(32);
let mut all_events = EnumSet::new();
for action in clip_actions {
all_events = &all_events | &action.events;
all_events |= action.events;
}
self.write_clip_event_flags(&all_events)?;
self.write_clip_event_flags(all_events)?;
}
for action in clip_actions {
self.write_clip_event_flags(&action.events)?;
self.write_clip_event_flags(action.events)?;
let action_length =
action.action_data.len() as u32 + if action.key_code.is_some() { 1 } else { 0 };
self.write_u32(action_length)?;
@ -2219,30 +2219,30 @@ impl<W: Write> Writer<W> {
Ok(())
}
fn write_clip_event_flags(&mut self, clip_events: &HashSet<ClipEvent>) -> Result<()> {
fn write_clip_event_flags(&mut self, clip_events: EnumSet<ClipEventFlag>) -> Result<()> {
// TODO: Assert proper version.
self.write_bit(clip_events.contains(&ClipEvent::KeyUp))?;
self.write_bit(clip_events.contains(&ClipEvent::KeyDown))?;
self.write_bit(clip_events.contains(&ClipEvent::MouseUp))?;
self.write_bit(clip_events.contains(&ClipEvent::MouseDown))?;
self.write_bit(clip_events.contains(&ClipEvent::MouseMove))?;
self.write_bit(clip_events.contains(&ClipEvent::Unload))?;
self.write_bit(clip_events.contains(&ClipEvent::EnterFrame))?;
self.write_bit(clip_events.contains(&ClipEvent::Load))?;
self.write_bit(clip_events.contains(&ClipEvent::DragOver))?;
self.write_bit(clip_events.contains(&ClipEvent::RollOut))?;
self.write_bit(clip_events.contains(&ClipEvent::RollOver))?;
self.write_bit(clip_events.contains(&ClipEvent::ReleaseOutside))?;
self.write_bit(clip_events.contains(&ClipEvent::Release))?;
self.write_bit(clip_events.contains(&ClipEvent::Press))?;
self.write_bit(clip_events.contains(&ClipEvent::Initialize))?;
self.write_bit(clip_events.contains(&ClipEvent::Data))?;
self.write_bit(clip_events.contains(ClipEventFlag::KeyUp))?;
self.write_bit(clip_events.contains(ClipEventFlag::KeyDown))?;
self.write_bit(clip_events.contains(ClipEventFlag::MouseUp))?;
self.write_bit(clip_events.contains(ClipEventFlag::MouseDown))?;
self.write_bit(clip_events.contains(ClipEventFlag::MouseMove))?;
self.write_bit(clip_events.contains(ClipEventFlag::Unload))?;
self.write_bit(clip_events.contains(ClipEventFlag::EnterFrame))?;
self.write_bit(clip_events.contains(ClipEventFlag::Load))?;
self.write_bit(clip_events.contains(ClipEventFlag::DragOver))?;
self.write_bit(clip_events.contains(ClipEventFlag::RollOut))?;
self.write_bit(clip_events.contains(ClipEventFlag::RollOver))?;
self.write_bit(clip_events.contains(ClipEventFlag::ReleaseOutside))?;
self.write_bit(clip_events.contains(ClipEventFlag::Release))?;
self.write_bit(clip_events.contains(ClipEventFlag::Press))?;
self.write_bit(clip_events.contains(ClipEventFlag::Initialize))?;
self.write_bit(clip_events.contains(ClipEventFlag::Data))?;
if self.version >= 6 {
self.write_ubits(5, 0)?;
let has_construct = self.version >= 7 && clip_events.contains(&ClipEvent::Construct);
let has_construct = self.version >= 7 && clip_events.contains(ClipEventFlag::Construct);
self.write_bit(has_construct)?;
self.write_bit(clip_events.contains(&ClipEvent::KeyPress))?;
self.write_bit(clip_events.contains(&ClipEvent::DragOut))?;
self.write_bit(clip_events.contains(ClipEventFlag::KeyPress))?;
self.write_bit(clip_events.contains(ClipEventFlag::DragOut))?;
self.write_u8(0)?;
}
self.flush_bits()?;