//! The data structures used in an Adobe SWF file. //! //! 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. /// This is returned by the `swf::read_swf` convenience method. #[derive(Debug, PartialEq)] pub struct Swf { pub header: Header, pub tags: Vec, } /// Returned by `read::read_swf_header`. Includes the decompress /// stream as well as the uncompressed data length. pub struct SwfStream<'a> { pub header: Header, pub uncompressed_length: usize, pub reader: crate::read::Reader>, } /// The header of an SWF file. /// /// Notably contains the compression format used by the rest of the SWF data. /// /// [SWF19 p.27](https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf#page=27) #[derive(Debug, PartialEq)] pub struct Header { pub version: u8, pub compression: Compression, pub stage_size: Rectangle, pub frame_rate: f32, pub num_frames: u16, } /// The compression foramt used internally by the SWF file. /// /// The vast majority of SWFs will use zlib compression. /// [SWF19 p.27](https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf#page=27) #[derive(Debug, PartialEq, Eq)] pub enum Compression { None, Zlib, Lzma, } /// Most coordinates in an SWF file are represented in "twips". /// A twip is 1/20th of a pixel. /// /// `Twips` is a type-safe wrapper type documenting where Twips are used /// in the SWF format. /// /// Use `Twips::from_pixels` and `Twips::to_pixels` to convert to and from /// pixel values. #[derive(Debug, PartialEq, Eq, Clone, Copy, Default, PartialOrd, Ord)] pub struct Twips(i32); impl Twips { /// There are 20 twips in a pixel. pub const TWIPS_PER_PIXEL: f64 = 20.0; /// Creates a new `Twips` object. Note that the `twips` value is in twips, /// not pixels. Use `from_pixels` to convert from pixel units. pub fn new>(twips: T) -> Self { Self(twips.into()) } /// Returns the number of twips. pub fn get(self) -> i32 { self.0 } /// Converts the number of pixels into twips. /// /// This may be a lossy conversion; any precision less than a twip (1/20 pixels) is truncated. pub fn from_pixels(pixels: f64) -> Self { Self((pixels * Self::TWIPS_PER_PIXEL) as i32) } /// Converts this twips value into pixel units. /// /// This is a lossless operation. pub fn to_pixels(self) -> f64 { f64::from(self.0) / Self::TWIPS_PER_PIXEL } } impl std::ops::Add for Twips { type Output = Self; fn add(self, other: Self) -> Self { Self(self.0 + other.0) } } impl std::ops::AddAssign for Twips { fn add_assign(&mut self, other: Self) { self.0 += other.0 } } impl std::ops::Sub for Twips { type Output = Self; fn sub(self, other: Self) -> Self { Self(self.0 - other.0) } } impl std::ops::SubAssign for Twips { fn sub_assign(&mut self, other: Self) { self.0 -= other.0 } } impl std::ops::Mul for Twips { type Output = Self; fn mul(self, other: i32) -> Self { Self(self.0 * other) } } impl std::ops::MulAssign for Twips { fn mul_assign(&mut self, other: i32) { self.0 *= other } } impl std::ops::Div for Twips { type Output = Self; fn div(self, other: i32) -> Self { Self(self.0 / other) } } impl std::ops::DivAssign for Twips { fn div_assign(&mut self, other: i32) { self.0 /= other } } impl std::fmt::Display for Twips { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.to_pixels()) } } #[derive(Debug, PartialEq, Clone, Default)] pub struct Rectangle { pub x_min: Twips, pub x_max: Twips, pub y_min: Twips, pub y_max: Twips, } #[derive(Debug, PartialEq, Clone)] pub struct Color { pub r: u8, pub g: u8, pub b: u8, pub a: u8, } #[derive(Debug, PartialEq, Clone)] pub struct ColorTransform { pub r_multiply: f32, pub g_multiply: f32, pub b_multiply: f32, pub a_multiply: f32, pub r_add: i16, pub g_add: i16, pub b_add: i16, pub a_add: i16, } impl ColorTransform { pub fn new() -> ColorTransform { ColorTransform { r_multiply: 1f32, g_multiply: 1f32, b_multiply: 1f32, a_multiply: 1f32, r_add: 0, g_add: 0, b_add: 0, a_add: 0, } } } impl Default for ColorTransform { fn default() -> Self { Self::new() } } #[derive(Debug, PartialEq, Clone)] pub struct Matrix { pub translate_x: Twips, pub translate_y: Twips, pub scale_x: f32, pub scale_y: f32, pub rotate_skew_0: f32, pub rotate_skew_1: f32, } impl Matrix { pub fn new() -> Matrix { Matrix { translate_x: Default::default(), translate_y: Default::default(), scale_x: 1f32, scale_y: 1f32, rotate_skew_0: 0f32, rotate_skew_1: 0f32, } } } impl Default for Matrix { fn default() -> Self { Self::new() } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Language { Unknown, Latin, Japanese, Korean, SimplifiedChinese, TraditionalChinese, } #[derive(Debug, PartialEq)] pub struct FileAttributes { pub use_direct_blit: bool, pub use_gpu: bool, pub has_metadata: bool, pub is_action_script_3: bool, pub use_network_sandbox: bool, } #[derive(Debug, PartialEq)] pub struct FrameLabel { pub label: String, pub is_anchor: bool, } #[derive(Debug, PartialEq)] pub struct DefineSceneAndFrameLabelData { pub scenes: Vec, pub frame_labels: Vec, } #[derive(Debug, PartialEq)] pub struct FrameLabelData { pub frame_num: u32, pub label: String, } pub type Depth = i16; pub type CharacterId = u16; #[derive(Debug, PartialEq)] pub struct PlaceObject { pub version: u8, pub action: PlaceObjectAction, pub depth: Depth, pub matrix: Option, pub color_transform: Option, pub ratio: Option, pub name: Option, pub clip_depth: Option, pub class_name: Option, pub filters: Vec, pub background_color: Option, pub blend_mode: BlendMode, pub clip_actions: Vec, pub is_image: bool, pub is_bitmap_cached: bool, pub is_visible: bool, pub amf_data: Option>, } #[derive(Debug, PartialEq, Clone, Copy)] pub enum PlaceObjectAction { Place(CharacterId), Modify, Replace(CharacterId), } #[derive(Debug, PartialEq, Clone)] pub enum Filter { DropShadowFilter(Box), BlurFilter(Box), GlowFilter(Box), BevelFilter(Box), GradientGlowFilter(Box), ConvolutionFilter(Box), ColorMatrixFilter(Box), GradientBevelFilter(Box), } #[derive(Debug, PartialEq, Clone)] pub struct DropShadowFilter { pub color: Color, pub blur_x: f64, pub blur_y: f64, pub angle: f64, pub distance: f64, pub strength: f32, pub is_inner: bool, pub is_knockout: bool, pub num_passes: u8, } #[derive(Debug, PartialEq, Clone)] pub struct BlurFilter { pub blur_x: f64, pub blur_y: f64, pub num_passes: u8, } #[derive(Debug, PartialEq, Clone)] pub struct GlowFilter { pub color: Color, pub blur_x: f64, pub blur_y: f64, pub strength: f32, pub is_inner: bool, pub is_knockout: bool, pub num_passes: u8, } #[derive(Debug, PartialEq, Clone)] pub struct BevelFilter { pub shadow_color: Color, pub highlight_color: Color, pub blur_x: f64, pub blur_y: f64, pub angle: f64, pub distance: f64, pub strength: f32, pub is_inner: bool, pub is_knockout: bool, pub is_on_top: bool, pub num_passes: u8, } #[derive(Debug, PartialEq, Clone)] pub struct GradientGlowFilter { pub colors: Vec, pub blur_x: f64, pub blur_y: f64, pub angle: f64, pub distance: f64, pub strength: f32, pub is_inner: bool, pub is_knockout: bool, pub is_on_top: bool, pub num_passes: u8, } #[derive(Debug, PartialEq, Clone)] pub struct ConvolutionFilter { pub num_matrix_rows: u8, pub num_matrix_cols: u8, pub matrix: Vec, pub divisor: f64, pub bias: f64, pub default_color: Color, pub is_clamped: bool, pub is_preserve_alpha: bool, } #[derive(Debug, PartialEq, Clone)] pub struct ColorMatrixFilter { pub matrix: [f64; 20], } #[derive(Debug, PartialEq, Clone)] pub struct GradientBevelFilter { pub colors: Vec, pub blur_x: f64, pub blur_y: f64, pub angle: f64, pub distance: f64, pub strength: f32, pub is_inner: bool, pub is_knockout: bool, pub is_on_top: bool, pub num_passes: u8, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum BlendMode { Normal, Layer, Multiply, Screen, Lighten, Darken, Difference, Add, Subtract, Invert, Alpha, Erase, Overlay, HardLight, } /// 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: EnumSet, pub key_code: Option, pub action_data: Vec, } /// 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, Press, RollOut, RollOver, Release, ReleaseOutside, Unload, } /// A key code used in `ButtonAction` and `ClipAction` key press events. pub type KeyCode = u8; /// Represents a tag in an SWF file. /// /// The SWF format is made up of a stream of tags. Each tag either /// defines a character (graphic, sound, movieclip), or places/modifies /// an instance of these characters on the display list. /// // [SWF19 p.29](https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf#page=29) #[derive(Debug, PartialEq)] pub enum Tag { ExportAssets(Vec), ScriptLimits { max_recursion_depth: u16, timeout_in_seconds: u16, }, ShowFrame, Protect(Option), CsmTextSettings(CsmTextSettings), DebugId(DebugId), DefineBinaryData { id: CharacterId, data: Vec, }, DefineBits { id: CharacterId, jpeg_data: Vec, }, DefineBitsJpeg2 { id: CharacterId, jpeg_data: Vec, }, DefineBitsJpeg3(DefineBitsJpeg3), DefineBitsLossless(DefineBitsLossless), DefineButton(Box