diff --git a/Cargo.lock b/Cargo.lock index fcdc8e7f0d0f..13f910cfa7f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4403,7 +4403,14 @@ dependencies = [ "fnv", "gc-arena", "hashbrown 0.14.5", + "quick-xml", + "regress", + "ruffle_macros", "ruffle_wstr", + "swf", + "thiserror 2.0.17", + "tracing", + "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7ab8912748d0..20446cd52b56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -75,6 +75,8 @@ num-traits = "0.2.19" serde = "1.0.228" thiserror = "2.0.17" url = "2.5.7" +quick-xml = "0.37.5" +regress = { git = "https://github.com/ruffle-rs/regras3", rev = "5fcb02513c5ab4e00df4346459f5a8d0521d8fed" } # Make sure to match wasm-bindgen-cli version to this everywhere. wasm-bindgen = "=0.2.101" walkdir = "2.5.0" diff --git a/core/Cargo.toml b/core/Cargo.toml index 11a324b7a950..8fac545cec25 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -30,7 +30,7 @@ bitflags = { workspace = true } smallvec = { workspace = true } num-traits = { workspace = true } num-derive = { workspace = true } -quick-xml = "0.37.5" +quick-xml = { workspace = true } url = { workspace = true } weak-table = "0.3.2" percent-encoding = { workspace = true } @@ -42,7 +42,7 @@ rand = { version = "0.9.1", features = ["std", "os_rng"], default-features = fal serde = { workspace = true } serde_json = { workspace = true, features = ["preserve_order"] } nellymoser-rs = { git = "https://github.com/ruffle-rs/nellymoser", rev = "073eb48d907201f46dea0c8feb4e8d9a1d92208c", optional = true } -regress = { git = "https://github.com/ruffle-rs/regras3", rev = "5fcb02513c5ab4e00df4346459f5a8d0521d8fed" } +regress = { workspace = true } flash-lso = { git = "https://github.com/ruffle-rs/rust-flash-lso", rev = "998f47c926b9986aabd518fbb7394ff56936d0b0" } lzma-rs = { workspace = true, optional = true } dasp = { version = "0.11.0", features = ["interpolate", "interpolate-linear", "signal"], optional = true } diff --git a/core/common/Cargo.toml b/core/common/Cargo.toml index 6ce8b64411e0..a33b68be96c6 100644 --- a/core/common/Cargo.toml +++ b/core/common/Cargo.toml @@ -14,4 +14,11 @@ workspace = true hashbrown = { workspace = true } fnv = { workspace = true } gc-arena = { workspace = true } +quick-xml = { workspace = true } +regress = { workspace = true } +ruffle_macros = { path = "../macros" } ruffle_wstr = { path = "../../wstr" } +swf = { path = "../../swf" } +thiserror = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } diff --git a/core/src/buffer.rs b/core/common/src/buffer.rs similarity index 100% rename from core/src/buffer.rs rename to core/common/src/buffer.rs diff --git a/core/common/src/lib.rs b/core/common/src/lib.rs index 86e6fb5ac271..c43b5fc5fdc8 100644 --- a/core/common/src/lib.rs +++ b/core/common/src/lib.rs @@ -1,3 +1,8 @@ -//! Types used across Ruffle +//! Methods and types used across Ruffle pub mod avm_string; +pub mod buffer; +pub mod sandbox; +pub mod tag_utils; +pub mod utils; +pub mod xml; diff --git a/core/src/sandbox.rs b/core/common/src/sandbox.rs similarity index 100% rename from core/src/sandbox.rs rename to core/common/src/sandbox.rs diff --git a/core/common/src/tag_utils.rs b/core/common/src/tag_utils.rs new file mode 100644 index 000000000000..fb7736da3b8f --- /dev/null +++ b/core/common/src/tag_utils.rs @@ -0,0 +1,474 @@ +use crate::sandbox::SandboxType; + +use gc_arena::Collect; +use std::fmt::{Debug, Formatter}; +use std::sync::Arc; +use swf::{Fixed8, HeaderExt, Rectangle, Twips}; +use url::Url; + +pub type SwfStream<'a> = swf::read::Reader<'a>; + +/// An open, fully parsed SWF movie ready to play back, either in a Player or a +/// MovieClip. +#[derive(Clone, Collect)] +#[collect(require_static)] +pub struct SwfMovie { + /// The SWF header parsed from the data stream. + header: HeaderExt, + + /// Uncompressed SWF data. + data: Vec, + + /// The URL the SWF was downloaded from. + url: String, + + /// The URL that triggered the SWF load. + loader_url: Option, + + /// Any parameters provided when loading this movie (also known as 'flashvars'), + /// as a list of key-value pairs. + parameters: Vec<(String, String)>, + + /// The suggest encoding for this SWF. + encoding: &'static swf::Encoding, + + /// The compressed length of the entire datastream + compressed_len: usize, + + /// Whether this SwfMovie actually represents a loaded movie or fills in for + /// something else, like an loaded image, filler movie, or error state. + is_movie: bool, + + /// Security sandbox type enforced for this movie. + /// + /// It absolutely cannot be changed after constructing + /// the object in order to ensure proper sandboxing. + sandbox_type: SandboxType, +} + +impl SwfMovie { + /// Construct an empty movie. + pub fn empty(swf_version: u8, loader_url: Option) -> Self { + let url = "file:///".to_string(); + let header = HeaderExt::default_with_swf_version(swf_version); + + // TODO What sandbox type should we use here? + let sandbox_type = SandboxType::infer(url.as_str(), &header); + Self { + header, + data: vec![], + url, + loader_url, + parameters: Vec::new(), + encoding: swf::UTF_8, + compressed_len: 0, + is_movie: false, + sandbox_type, + } + } + + /// Construct an empty movie with a fake `compressed_len`. + /// This is used by `Loader` when firing an initial `progress` event: + /// `LoaderInfo.bytesTotal` is set to the actual value, but no data is available, + /// and `LoaderInfo.parameters` is empty. + pub fn fake_with_compressed_len( + swf_version: u8, + loader_url: Option, + compressed_len: usize, + ) -> Self { + let url = "file:///".to_string(); + let header = HeaderExt::default_with_swf_version(swf_version); + + // TODO What sandbox type should we use here? + let sandbox_type = SandboxType::infer(url.as_str(), &header); + Self { + header, + compressed_len, + data: Vec::new(), + url, + loader_url, + parameters: Vec::new(), + encoding: swf::UTF_8, + is_movie: false, + sandbox_type, + } + } + + /// Like `fake_with_compressed_len`, but uses actual data. + /// This is used when loading a Bitmap to expose the underlying content + pub fn fake_with_compressed_data( + swf_version: u8, + loader_url: Option, + compressed_data: Vec, + ) -> Self { + let url = "file:///".to_string(); + let header = HeaderExt::default_with_swf_version(swf_version); + + // TODO What sandbox type should we use here? + let sandbox_type = SandboxType::infer(url.as_str(), &header); + Self { + header, + compressed_len: compressed_data.len(), + data: compressed_data, + url, + loader_url, + parameters: Vec::new(), + encoding: swf::UTF_8, + is_movie: false, + sandbox_type, + } + } + + /// Constructs the error state movie stub in which some attributes have certain + /// error values to signal that no valid file could be loaded. + /// + /// This happens if no file could be loaded or if the loaded content is no valid + /// supported content. + pub fn error_movie(movie_url: String) -> Self { + let header = HeaderExt::default_error_header(); + + // TODO What sandbox type should we use here? + let sandbox_type = SandboxType::infer(movie_url.as_str(), &header); + Self { + header, + data: vec![], + url: movie_url, + loader_url: None, + parameters: Vec::new(), + encoding: swf::UTF_8, + compressed_len: 0, + is_movie: false, + sandbox_type, + } + } + + /// Construct a movie based on the contents of the SWF datastream. + pub fn from_data( + swf_data: &[u8], + url: String, + loader_url: Option, + ) -> Result { + let compressed_len = swf_data.len(); + let swf_buf = swf::read::decompress_swf(swf_data)?; + let encoding = swf::SwfStr::encoding_for_version(swf_buf.header.version()); + let sandbox_type = SandboxType::infer(url.as_str(), &swf_buf.header); + let mut movie = Self { + header: swf_buf.header, + data: swf_buf.data, + url, + loader_url, + parameters: Vec::new(), + encoding, + compressed_len, + is_movie: true, + sandbox_type, + }; + movie.append_parameters_from_url(); + Ok(movie) + } + + /// Construct a movie based on a loaded image (JPEG, GIF or PNG). + pub fn from_loaded_image(url: String, length: usize) -> Self { + let header = HeaderExt::default_with_uncompressed_len(length as i32); + let sandbox_type = SandboxType::infer(url.as_str(), &header); + let mut movie = Self { + header, + data: vec![], + url, + loader_url: None, + parameters: Vec::new(), + encoding: swf::UTF_8, + compressed_len: length, + is_movie: false, + sandbox_type, + }; + movie.append_parameters_from_url(); + movie + } + + fn append_parameters_from_url(&mut self) { + match Url::parse(&self.url) { + Ok(url) => { + for (key, value) in url.query_pairs() { + self.parameters.push((key.into_owned(), value.into_owned())); + } + } + Err(e) => { + tracing::error!( + "Failed to parse loader URL when extracting query parameters: {}", + e + ); + } + } + } + + pub fn header(&self) -> &HeaderExt { + &self.header + } + + /// Get the version of the SWF. + pub fn version(&self) -> u8 { + self.header.version() + } + + pub fn data(&self) -> &[u8] { + &self.data + } + + /// Returns the suggested string encoding for the given SWF version. + /// For SWF version 6 and higher, this is always UTF-8. + /// For SWF version 5 and lower, this is locale-dependent, + /// and we default to WINDOWS-1252. + pub fn encoding(&self) -> &'static swf::Encoding { + self.encoding + } + + /// The width of the movie in twips. + pub fn width(&self) -> Twips { + self.header.stage_size().width() + } + + /// The height of the movie in twips. + pub fn height(&self) -> Twips { + self.header.stage_size().height() + } + + /// Get the URL this SWF was fetched from. + pub fn url(&self) -> &str { + &self.url + } + + pub fn set_url(&mut self, url: String) { + self.url = url; + } + + /// Get the URL that triggered the fetch of this SWF. + pub fn loader_url(&self) -> Option<&str> { + self.loader_url.as_deref() + } + + pub fn parameters(&self) -> &[(String, String)] { + &self.parameters + } + + pub fn append_parameters(&mut self, params: impl IntoIterator) { + self.parameters.extend(params); + } + + pub fn compressed_len(&self) -> usize { + self.compressed_len + } + + pub fn uncompressed_len(&self) -> i32 { + self.header.uncompressed_len() + } + + pub fn is_action_script_3(&self) -> bool { + self.header.is_action_script_3() + } + + pub fn stage_size(&self) -> &Rectangle { + self.header.stage_size() + } + + pub fn num_frames(&self) -> u16 { + self.header.num_frames() + } + + pub fn frame_rate(&self) -> Fixed8 { + self.header.frame_rate() + } + + pub fn is_movie(&self) -> bool { + self.is_movie + } + + pub fn sandbox_type(&self) -> SandboxType { + self.sandbox_type + } +} + +impl Debug for SwfMovie { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SwfMovie") + .field("header", &self.header) + .field("data", &self.data.len()) + .field("url", &self.url) + .field("loader_url", &self.loader_url) + .field("parameters", &self.parameters) + .field("encoding", &self.encoding) + .field("compressed_len", &self.compressed_len) + .field("is_movie", &self.is_movie) + .field("sandbox_type", &self.sandbox_type) + .finish() + } +} + +/// A shared-ownership reference to some portion of an SWF datastream. +#[derive(Debug, Clone, Collect)] +#[collect(no_drop)] +pub struct SwfSlice { + pub movie: Arc, + pub start: usize, + pub end: usize, +} + +impl From> for SwfSlice { + fn from(movie: Arc) -> Self { + let end = movie.data().len(); + + Self { + movie, + start: 0, + end, + } + } +} + +impl AsRef<[u8]> for SwfSlice { + #[inline] + fn as_ref(&self) -> &[u8] { + self.data() + } +} + +impl SwfSlice { + /// Creates an empty SwfSlice. + #[inline] + pub fn empty(movie: Arc) -> Self { + Self { + movie, + start: 0, + end: 0, + } + } + + /// Creates an empty SwfSlice of the same movie. + #[inline] + pub fn copy_empty(&self) -> Self { + Self::empty(self.movie.clone()) + } + + /// Construct a new SwfSlice from a regular slice. + /// + /// This function returns None if the given slice is not a subslice of the + /// current slice. + pub fn to_subslice(&self, slice: &[u8]) -> Self { + let self_pval = self.movie.data().as_ptr() as usize; + let slice_pval = slice.as_ptr() as usize; + + if (self_pval + self.start) <= slice_pval && slice_pval < (self_pval + self.end) { + Self { + movie: self.movie.clone(), + start: slice_pval - self_pval, + end: (slice_pval - self_pval) + slice.len(), + } + } else { + self.copy_empty() + } + } + + /// Construct a new SwfSlice from a movie subslice. + /// + /// This function allows subslices outside the current slice to be formed, + /// as long as they are valid subslices of the movie itself. + pub fn to_unbounded_subslice(&self, slice: &[u8]) -> Self { + let self_pval = self.movie.data().as_ptr() as usize; + let self_len = self.movie.data().len(); + let slice_pval = slice.as_ptr() as usize; + + if self_pval <= slice_pval && slice_pval < (self_pval + self_len) { + Self { + movie: self.movie.clone(), + start: slice_pval - self_pval, + end: (slice_pval - self_pval) + slice.len(), + } + } else { + self.copy_empty() + } + } + + /// Construct a new SwfSlice from a Reader and a size. + /// + /// This is intended to allow constructing references to the contents of a + /// given SWF tag. You just need the current reader and the size of the tag + /// you want to reference. + /// + /// The returned slice may or may not be a subslice of the current slice. + /// If the resulting slice would be outside the bounds of the underlying + /// movie, or the given reader refers to a different underlying movie, this + /// function returns an empty slice. + pub fn resize_to_reader(&self, reader: &mut SwfStream<'_>, size: usize) -> Self { + if self.movie.data().as_ptr() as usize <= reader.get_ref().as_ptr() as usize + && (reader.get_ref().as_ptr() as usize) + < self.movie.data().as_ptr() as usize + self.movie.data().len() + { + let outer_offset = + reader.get_ref().as_ptr() as usize - self.movie.data().as_ptr() as usize; + let new_start = outer_offset; + let new_end = outer_offset + size; + + let len = self.movie.data().len(); + + if new_start < len && new_end < len { + Self { + movie: self.movie.clone(), + start: new_start, + end: new_end, + } + } else { + self.copy_empty() + } + } else { + self.copy_empty() + } + } + + /// Construct a new SwfSlice from a start and an end. + /// + /// The start and end values will be relative to the current slice. + /// Furthermore, this function will yield an empty slice if the calculated slice + /// would be invalid (e.g. negative length) or would extend past the end of + /// the current slice. + pub fn to_start_and_end(&self, start: usize, end: usize) -> Self { + let new_start = self.start + start; + let new_end = self.start + end; + + if new_start <= new_end { + if let Some(result) = self.movie.data().get(new_start..new_end) { + self.to_subslice(result) + } else { + self.copy_empty() + } + } else { + self.copy_empty() + } + } + + /// Convert the SwfSlice into a standard data slice. + pub fn data(&self) -> &[u8] { + &self.movie.data()[self.start..self.end] + } + + /// Get the version of the SWF this data comes from. + pub fn version(&self) -> u8 { + self.movie.header().version() + } + + /// Checks if this slice is empty + pub fn is_empty(&self) -> bool { + self.end == self.start + } + + /// Construct a reader for this slice. + /// + /// The `from` parameter is the offset to start reading the slice from. + pub fn read_from(&self, from: u64) -> swf::read::Reader<'_> { + swf::read::Reader::new(&self.data()[from as usize..], self.movie.version()) + } + + /// Get the length of the SwfSlice. + pub fn len(&self) -> usize { + self.end - self.start + } +} diff --git a/core/src/utils.rs b/core/common/src/utils.rs similarity index 100% rename from core/src/utils.rs rename to core/common/src/utils.rs diff --git a/core/src/xml.rs b/core/common/src/xml.rs similarity index 100% rename from core/src/xml.rs rename to core/common/src/xml.rs diff --git a/core/macros/src/lib.rs b/core/macros/src/lib.rs index 186ac2d85243..c5e422c09018 100644 --- a/core/macros/src/lib.rs +++ b/core/macros/src/lib.rs @@ -297,7 +297,7 @@ pub fn derive_has_prefix_field(input: TokenStream) -> TokenStream { // for a worked-out example), so we add post-mono checks as a latch-ditch guard. #[automatically_derived] unsafe impl #impl_generics - crate::utils::HasPrefixField<#field_ty> + ruffle_common::utils::HasPrefixField<#field_ty> for #ty #ty_generics #where_clause { const ASSERT_PREFIX_FIELD: () = { ::core::assert!(::core::mem::offset_of!(Self, #field_name) == 0); diff --git a/core/src/avm1/globals/system_security.rs b/core/src/avm1/globals/system_security.rs index c155b903d0bf..8e2e010db293 100644 --- a/core/src/avm1/globals/system_security.rs +++ b/core/src/avm1/globals/system_security.rs @@ -4,9 +4,10 @@ use crate::avm1::property_decl::{DeclContext, Declaration}; use crate::avm1::{Object, Value}; use crate::avm1_stub; use crate::prelude::TDisplayObject; -use crate::sandbox::SandboxType; use crate::string::AvmString; +use ruffle_common::sandbox::SandboxType; + const OBJECT_DECLS: &[Declaration] = declare_properties! { "PolicyFileResolver" => method(policy_file_resolver); "allowDomain" => method(allow_domain); diff --git a/core/src/avm1/globals/xml.rs b/core/src/avm1/globals/xml.rs index 93632a50e9a9..fae9b616a87d 100644 --- a/core/src/avm1/globals/xml.rs +++ b/core/src/avm1/globals/xml.rs @@ -9,13 +9,13 @@ use crate::avm1::{Activation, Attribute, Error, NativeObject, Object, Value}; use crate::avm_warn; use crate::backend::navigator::Request; use crate::string::{AvmString, StringContext, WStr, WString}; -use crate::xml::custom_unescape; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc}; use quick_xml::errors::IllFormedError; use quick_xml::events::attributes::AttrError; use quick_xml::{events::Event, Reader}; +use ruffle_common::xml::custom_unescape; use ruffle_macros::istr; #[derive(Clone, Copy, Collect)] diff --git a/core/src/avm1/object/super_object.rs b/core/src/avm1/object/super_object.rs index 22526349746f..343dbe9f14ec 100644 --- a/core/src/avm1/object/super_object.rs +++ b/core/src/avm1/object/super_object.rs @@ -26,7 +26,7 @@ pub struct SuperObject<'gc> { depth: u8, /// Adds a niche, so that enums contaning this type can use it for their discriminant. - _niche: crate::utils::ZeroU8, + _niche: ruffle_common::utils::ZeroU8, } impl fmt::Debug for SuperObject<'_> { diff --git a/core/src/avm1/xml/tree.rs b/core/src/avm1/xml/tree.rs index b9e26db6a655..07131669c118 100644 --- a/core/src/avm1/xml/tree.rs +++ b/core/src/avm1/xml/tree.rs @@ -10,6 +10,7 @@ use gc_arena::{ }; use quick_xml::escape::escape; use quick_xml::events::BytesStart; +use ruffle_common::xml::custom_unescape; use ruffle_macros::istr; use std::cell::RefMut; use std::fmt; @@ -92,7 +93,7 @@ impl<'gc> XmlNode<'gc> { let attributes = attributes?; for attribute in attributes.iter().rev() { let key = AvmString::new_utf8_bytes(activation.gc(), attribute.key.into_inner()); - let value_str = crate::xml::custom_unescape(&attribute.value, decoder)?; + let value_str = custom_unescape(&attribute.value, decoder)?; let value = AvmString::new_utf8_bytes(activation.gc(), value_str.as_bytes()); // Insert an attribute. diff --git a/core/src/avm2/e4x.rs b/core/src/avm2/e4x.rs index 27198fae3695..e6c63d10a847 100644 --- a/core/src/avm2/e4x.rs +++ b/core/src/avm2/e4x.rs @@ -3,7 +3,6 @@ use crate::avm2::function::FunctionArgs; use crate::avm2::object::{E4XOrXml, FunctionObject, NamespaceObject}; use crate::avm2::{Activation, Error, Multiname, Value}; use crate::string::{AvmString, StringContext, WStr, WString}; -use crate::xml::custom_unescape; use gc_arena::barrier::unlock; use gc_arena::{ @@ -17,6 +16,7 @@ use quick_xml::{ name::ResolveResult, Error as XmlError, NsReader, }; +use ruffle_common::xml::custom_unescape; use ruffle_macros::istr; use std::cell::{Ref, RefMut}; diff --git a/core/src/avm2/globals/flash/system/security.rs b/core/src/avm2/globals/flash/system/security.rs index 374c5bbf3eab..27985d60d455 100644 --- a/core/src/avm2/globals/flash/system/security.rs +++ b/core/src/avm2/globals/flash/system/security.rs @@ -4,10 +4,11 @@ use crate::avm2::activation::Activation; use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2_stub_method; -use crate::sandbox::SandboxType; use crate::string::AvmString; use url::Url; +use ruffle_common::sandbox::SandboxType; + pub fn get_page_domain<'gc>( activation: &mut Activation<'_, 'gc>, _this: Value<'gc>, diff --git a/core/src/avm2/object/array_object.rs b/core/src/avm2/object/array_object.rs index b3fd6452e59c..c82c30aa9a97 100644 --- a/core/src/avm2/object/array_object.rs +++ b/core/src/avm2/object/array_object.rs @@ -8,10 +8,10 @@ use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; use crate::string::{AvmString, WStr}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Ref, RefMut}; /// A class instance allocator that allocates array objects. diff --git a/core/src/avm2/object/bitmapdata_object.rs b/core/src/avm2/object/bitmapdata_object.rs index 89f3ca8e5a50..2d181a9a6b3d 100644 --- a/core/src/avm2/object/bitmapdata_object.rs +++ b/core/src/avm2/object/bitmapdata_object.rs @@ -6,10 +6,10 @@ use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; use crate::bitmap::bitmap_data::BitmapData; use crate::context::UpdateContext; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; /// A class instance allocator that allocates BitmapData objects. pub fn bitmap_data_allocator<'gc>( diff --git a/core/src/avm2/object/bytearray_object.rs b/core/src/avm2/object/bytearray_object.rs index afd24b0e4510..c04450b3ad0a 100644 --- a/core/src/avm2/object/bytearray_object.rs +++ b/core/src/avm2/object/bytearray_object.rs @@ -6,10 +6,9 @@ use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; use crate::character::Character; -use crate::tag_utils::SwfSlice; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Ref, RefCell, RefMut}; /// A class instance allocator that allocates ByteArray objects. @@ -27,7 +26,7 @@ pub fn byte_array_allocator<'gc>( if let Some(Character::BinaryData(binary_data)) = lib.character_by_id(id) { Some(ByteArrayStorage::from_vec( activation.context, - SwfSlice::as_ref(&binary_data).to_vec(), + binary_data.to_vec(), )) } else { None diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index 55eb2df93f6a..376d2d62c439 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -19,13 +19,13 @@ use crate::avm2::Multiname; use crate::avm2::QName; use crate::avm2::TranslationUnit; use crate::string::AvmString; -use crate::utils::HasPrefixField; use fnv::FnvHashMap; use gc_arena::barrier::unlock; use gc_arena::{ lock::{Lock, RefLock}, Collect, Gc, GcWeak, Mutation, }; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use std::fmt::Debug; use std::hash::{Hash, Hasher}; diff --git a/core/src/avm2/object/context3d_object.rs b/core/src/avm2/object/context3d_object.rs index 6ea6dc5f5562..d5333608da3d 100644 --- a/core/src/avm2/object/context3d_object.rs +++ b/core/src/avm2/object/context3d_object.rs @@ -8,8 +8,8 @@ use crate::avm2::Error; use crate::avm2_stub_method; use crate::bitmap::bitmap_data::BitmapRawData; use crate::context::RenderContext; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::{ BufferUsage, Context3D, Context3DBlendFactor, Context3DCommand, Context3DCompareMode, Context3DTextureFormat, Context3DTriangleFace, Context3DVertexBufferFormat, ProgramType, diff --git a/core/src/avm2/object/date_object.rs b/core/src/avm2/object/date_object.rs index 05a275c62e3e..beced1ebeb4a 100644 --- a/core/src/avm2/object/date_object.rs +++ b/core/src/avm2/object/date_object.rs @@ -3,10 +3,10 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::value::Hint; use crate::avm2::Error; -use crate::utils::HasPrefixField; use chrono::{DateTime, Utc}; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::cell::Cell; /// A class instance allocator that allocates Date objects. diff --git a/core/src/avm2/object/dictionary_object.rs b/core/src/avm2/object/dictionary_object.rs index 8d84e43cae8f..0318f663e740 100644 --- a/core/src/avm2/object/dictionary_object.rs +++ b/core/src/avm2/object/dictionary_object.rs @@ -7,9 +7,9 @@ use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::AvmString; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; /// A class instance allocator that allocates Dictionary objects. pub fn dictionary_allocator<'gc>( diff --git a/core/src/avm2/object/dispatch_object.rs b/core/src/avm2/object/dispatch_object.rs index 5c38c1587cd4..816bb5b604bf 100644 --- a/core/src/avm2/object/dispatch_object.rs +++ b/core/src/avm2/object/dispatch_object.rs @@ -4,10 +4,10 @@ use crate::avm2::activation::Activation; use crate::avm2::events::DispatchList; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, TObject}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::cell::RefMut; /// Internal representation of dispatch lists as generated by `EventDispatcher`. diff --git a/core/src/avm2/object/domain_object.rs b/core/src/avm2/object/domain_object.rs index b7c62d0acad5..5553907f5ee2 100644 --- a/core/src/avm2/object/domain_object.rs +++ b/core/src/avm2/object/domain_object.rs @@ -5,10 +5,10 @@ use crate::avm2::domain::Domain; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; /// A class instance allocator that allocates AppDomain objects. pub fn application_domain_allocator<'gc>( diff --git a/core/src/avm2/object/error_object.rs b/core/src/avm2/object/error_object.rs index fb3703bf6d41..151d1711426a 100644 --- a/core/src/avm2/object/error_object.rs +++ b/core/src/avm2/object/error_object.rs @@ -8,9 +8,9 @@ use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::{WStr, WString}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::fmt::Debug; /// A class instance allocator that allocates Error objects. diff --git a/core/src/avm2/object/event_object.rs b/core/src/avm2/object/event_object.rs index 8cd0ca40ae37..6cfdcf1c3b89 100644 --- a/core/src/avm2/object/event_object.rs +++ b/core/src/avm2/object/event_object.rs @@ -11,9 +11,9 @@ use crate::display_object::TDisplayObject; use crate::display_object::{DisplayObject, InteractiveObject, TInteractiveObject}; use crate::events::{KeyCode, MouseButton}; use crate::string::AvmString; -use crate::utils::HasPrefixField; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use std::cell::{Ref, RefMut}; use std::fmt::Debug; diff --git a/core/src/avm2/object/file_reference_object.rs b/core/src/avm2/object/file_reference_object.rs index 2608be402595..9b419b490005 100644 --- a/core/src/avm2/object/file_reference_object.rs +++ b/core/src/avm2/object/file_reference_object.rs @@ -3,8 +3,8 @@ use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::{Activation, Error}; use crate::backend::ui::FileDialogResult; use crate::context::UpdateContext; -use crate::utils::HasPrefixField; use gc_arena::{Collect, DynamicRoot, Gc, GcWeak, Rootable}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Cell, Ref, RefCell}; use std::fmt; diff --git a/core/src/avm2/object/font_object.rs b/core/src/avm2/object/font_object.rs index 48d002a70c8a..5b282d126e2e 100644 --- a/core/src/avm2/object/font_object.rs +++ b/core/src/avm2/object/font_object.rs @@ -3,8 +3,8 @@ use crate::avm2::object::{Object, TObject}; use crate::avm2::{Activation, ClassObject, Error}; use crate::character::Character; use crate::font::Font; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::fmt; /// A class instance allocator that allocates Font objects. diff --git a/core/src/avm2/object/function_object.rs b/core/src/avm2/object/function_object.rs index 183b651c1c53..4b2573b0386e 100644 --- a/core/src/avm2/object/function_object.rs +++ b/core/src/avm2/object/function_object.rs @@ -9,10 +9,10 @@ use crate::avm2::scope::ScopeChain; use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::AvmString; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; /// An Object which can be called to execute its function code. diff --git a/core/src/avm2/object/index_buffer_3d_object.rs b/core/src/avm2/object/index_buffer_3d_object.rs index 93cb8fc9a6b1..9b51a878c495 100644 --- a/core/src/avm2/object/index_buffer_3d_object.rs +++ b/core/src/avm2/object/index_buffer_3d_object.rs @@ -3,8 +3,8 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, TObject}; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::IndexBuffer; use std::cell::{Cell, RefCell, RefMut}; diff --git a/core/src/avm2/object/loaderinfo_object.rs b/core/src/avm2/object/loaderinfo_object.rs index eb983a164725..9dbbca641c55 100644 --- a/core/src/avm2/object/loaderinfo_object.rs +++ b/core/src/avm2/object/loaderinfo_object.rs @@ -8,13 +8,13 @@ use crate::context::UpdateContext; use crate::display_object::DisplayObject; use crate::loader::ContentType; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{ lock::{Lock, RefLock}, Collect, Gc, GcWeak, Mutation, }; +use ruffle_common::utils::HasPrefixField; use std::cell::{Cell, Ref}; use std::sync::Arc; diff --git a/core/src/avm2/object/local_connection_object.rs b/core/src/avm2/object/local_connection_object.rs index 950cf52806c0..e8e7e9239627 100644 --- a/core/src/avm2/object/local_connection_object.rs +++ b/core/src/avm2/object/local_connection_object.rs @@ -8,11 +8,11 @@ use crate::avm2::{Avm2, Domain, Error}; use crate::context::UpdateContext; use crate::local_connection::{LocalConnectionHandle, LocalConnections}; use crate::string::AvmString; -use crate::utils::HasPrefixField; use core::fmt; use flash_lso::types::Value as AmfValue; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use std::cell::RefCell; diff --git a/core/src/avm2/object/message_channel_object.rs b/core/src/avm2/object/message_channel_object.rs index 7065afb369b5..0f495f111f21 100644 --- a/core/src/avm2/object/message_channel_object.rs +++ b/core/src/avm2/object/message_channel_object.rs @@ -1,9 +1,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::TObject; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; #[derive(Clone, Collect, Copy)] #[collect(no_drop)] diff --git a/core/src/avm2/object/namespace_object.rs b/core/src/avm2/object/namespace_object.rs index af4fb2b2718f..e213b1657658 100644 --- a/core/src/avm2/object/namespace_object.rs +++ b/core/src/avm2/object/namespace_object.rs @@ -7,9 +7,9 @@ use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Namespace; use crate::string::AvmString; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; /// An Object which represents a boxed namespace name. diff --git a/core/src/avm2/object/net_connection_object.rs b/core/src/avm2/object/net_connection_object.rs index 8812a0f4e5d5..396c4a3ee542 100644 --- a/core/src/avm2/object/net_connection_object.rs +++ b/core/src/avm2/object/net_connection_object.rs @@ -5,8 +5,8 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; use crate::net_connection::NetConnectionHandle; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::cell::Cell; use std::fmt; use std::fmt::Debug; diff --git a/core/src/avm2/object/netstream_object.rs b/core/src/avm2/object/netstream_object.rs index f8072d75950b..978ee0fcbfc0 100644 --- a/core/src/avm2/object/netstream_object.rs +++ b/core/src/avm2/object/netstream_object.rs @@ -5,8 +5,8 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; use crate::streams::NetStream; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::fmt::Debug; pub fn netstream_allocator<'gc>( diff --git a/core/src/avm2/object/program_3d_object.rs b/core/src/avm2/object/program_3d_object.rs index 1fcc2c6c5791..35fee58153b1 100644 --- a/core/src/avm2/object/program_3d_object.rs +++ b/core/src/avm2/object/program_3d_object.rs @@ -3,8 +3,8 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, TObject}; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::ShaderModule; use std::cell::RefCell; use std::rc::Rc; diff --git a/core/src/avm2/object/proxy_object.rs b/core/src/avm2/object/proxy_object.rs index f67578414cb2..de1573fb4312 100644 --- a/core/src/avm2/object/proxy_object.rs +++ b/core/src/avm2/object/proxy_object.rs @@ -9,9 +9,9 @@ use crate::avm2::string::AvmString; use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; /// A class instance allocator that allocates Proxy objects. diff --git a/core/src/avm2/object/qname_object.rs b/core/src/avm2/object/qname_object.rs index 61e8d113211d..2392d420166c 100644 --- a/core/src/avm2/object/qname_object.rs +++ b/core/src/avm2/object/qname_object.rs @@ -9,10 +9,10 @@ use crate::avm2::Error; use crate::avm2::Multiname; use crate::avm2::Namespace; use crate::string::StringContext; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use std::cell::Ref; diff --git a/core/src/avm2/object/regexp_object.rs b/core/src/avm2/object/regexp_object.rs index b5c07244965d..05b3f2512236 100644 --- a/core/src/avm2/object/regexp_object.rs +++ b/core/src/avm2/object/regexp_object.rs @@ -5,10 +5,10 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::regexp::RegExp; use crate::avm2::Error; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use std::cell::{Ref, RefMut}; diff --git a/core/src/avm2/object/responder_object.rs b/core/src/avm2/object/responder_object.rs index 8e1f5ac25cab..c531cba97f88 100644 --- a/core/src/avm2/object/responder_object.rs +++ b/core/src/avm2/object/responder_object.rs @@ -4,10 +4,10 @@ use crate::avm2::object::{ClassObject, FunctionObject, Object, TObject}; use crate::avm2::{Activation, Error}; use crate::context::UpdateContext; use crate::net_connection::ResponderCallback; -use crate::utils::HasPrefixField; use flash_lso::types::Value as AMFValue; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::fmt; /// A class instance allocator that allocates Responder objects. diff --git a/core/src/avm2/object/security_domain_object.rs b/core/src/avm2/object/security_domain_object.rs index e0ea15469d4c..4cd834010d0c 100644 --- a/core/src/avm2/object/security_domain_object.rs +++ b/core/src/avm2/object/security_domain_object.rs @@ -1,9 +1,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::TObject; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; #[derive(Clone, Collect, Copy)] #[collect(no_drop)] diff --git a/core/src/avm2/object/shader_data_object.rs b/core/src/avm2/object/shader_data_object.rs index aa97ac07aeaf..ae7d61ee8912 100644 --- a/core/src/avm2/object/shader_data_object.rs +++ b/core/src/avm2/object/shader_data_object.rs @@ -4,9 +4,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::pixel_bender::PixelBenderShaderHandle; use std::cell::Cell; diff --git a/core/src/avm2/object/shared_object_object.rs b/core/src/avm2/object/shared_object_object.rs index 93569d70dd68..160932c83966 100644 --- a/core/src/avm2/object/shared_object_object.rs +++ b/core/src/avm2/object/shared_object_object.rs @@ -3,9 +3,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ScriptObject, TObject}; -use crate::utils::HasPrefixField; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::fmt::Debug; #[derive(Clone, Collect, Copy)] diff --git a/core/src/avm2/object/socket_object.rs b/core/src/avm2/object/socket_object.rs index be5cfe60f2eb..433795ad3325 100644 --- a/core/src/avm2/object/socket_object.rs +++ b/core/src/avm2/object/socket_object.rs @@ -4,9 +4,9 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Activation; use crate::socket::SocketHandle; -use crate::utils::HasPrefixField; use gc_arena::GcWeak; use gc_arena::{Collect, Gc}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Cell, RefCell, RefMut}; use std::fmt; diff --git a/core/src/avm2/object/sound_object.rs b/core/src/avm2/object/sound_object.rs index 3eee96c35232..f3959e2be968 100644 --- a/core/src/avm2/object/sound_object.rs +++ b/core/src/avm2/object/sound_object.rs @@ -11,7 +11,6 @@ use crate::backend::audio::{AudioManager, SoundHandle}; use crate::context::UpdateContext; use crate::display_object::SoundTransform; use crate::string::AvmString; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{ @@ -19,6 +18,7 @@ use gc_arena::{ Collect, DynamicRoot, Gc, GcWeak, Mutation, Rootable, }; use id3::{Tag, TagLike}; +use ruffle_common::utils::HasPrefixField; use std::cell::Cell; use std::io::Cursor; use swf::SoundInfo; diff --git a/core/src/avm2/object/soundchannel_object.rs b/core/src/avm2/object/soundchannel_object.rs index bc08daee9925..e008bd78ec61 100644 --- a/core/src/avm2/object/soundchannel_object.rs +++ b/core/src/avm2/object/soundchannel_object.rs @@ -7,9 +7,9 @@ use crate::avm2::Error; use crate::backend::audio::SoundInstanceHandle; use crate::context::UpdateContext; use crate::display_object::SoundTransform; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Cell, RefCell}; /// A class instance allocator that allocates SoundChannel objects. diff --git a/core/src/avm2/object/soundtransform_object.rs b/core/src/avm2/object/soundtransform_object.rs index 318af927b2b0..4e109c74b2df 100644 --- a/core/src/avm2/object/soundtransform_object.rs +++ b/core/src/avm2/object/soundtransform_object.rs @@ -2,9 +2,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::cell::Cell; /// A class instance allocator that allocates SoundTransform objects. diff --git a/core/src/avm2/object/stage3d_object.rs b/core/src/avm2/object/stage3d_object.rs index 3339955a1e37..99cb11e513ff 100644 --- a/core/src/avm2/object/stage3d_object.rs +++ b/core/src/avm2/object/stage3d_object.rs @@ -3,11 +3,11 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, TObject}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::cell::Cell; #[derive(Clone, Collect, Copy)] diff --git a/core/src/avm2/object/stage_object.rs b/core/src/avm2/object/stage_object.rs index 547034f4fa21..aa1810ed8386 100644 --- a/core/src/avm2/object/stage_object.rs +++ b/core/src/avm2/object/stage_object.rs @@ -6,8 +6,8 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, TObject}; use crate::avm2::Error; use crate::display_object::DisplayObject; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::fmt::Debug; #[derive(Clone, Collect, Copy)] diff --git a/core/src/avm2/object/stylesheet_object.rs b/core/src/avm2/object/stylesheet_object.rs index cd157f6f9a75..dd93872de6c6 100644 --- a/core/src/avm2/object/stylesheet_object.rs +++ b/core/src/avm2/object/stylesheet_object.rs @@ -3,9 +3,9 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; use crate::html::{StyleSheet, TextFormat}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_wstr::{WStr, WString}; /// A class instance allocator that allocates StyleSheet objects. diff --git a/core/src/avm2/object/textformat_object.rs b/core/src/avm2/object/textformat_object.rs index 72d45143a5c7..4ab8255bbb33 100644 --- a/core/src/avm2/object/textformat_object.rs +++ b/core/src/avm2/object/textformat_object.rs @@ -5,9 +5,9 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, TObject}; use crate::avm2::Error; use crate::html::{TextDisplay, TextFormat}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Ref, RefCell, RefMut}; /// A class instance allocator that allocates TextFormat objects. diff --git a/core/src/avm2/object/texture_object.rs b/core/src/avm2/object/texture_object.rs index 75a551a7e236..3c87c6352689 100644 --- a/core/src/avm2/object/texture_object.rs +++ b/core/src/avm2/object/texture_object.rs @@ -3,8 +3,8 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, TObject}; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::{Context3DTextureFormat, Texture}; use std::rc::Rc; diff --git a/core/src/avm2/object/vector_object.rs b/core/src/avm2/object/vector_object.rs index d2df179ab5e6..b0e113aada3e 100644 --- a/core/src/avm2/object/vector_object.rs +++ b/core/src/avm2/object/vector_object.rs @@ -8,10 +8,10 @@ use crate::avm2::value::Value; use crate::avm2::vector::VectorStorage; use crate::avm2::Multiname; use crate::string::WStr; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Ref, RefMut}; /// A class instance allocator that allocates Vector objects. diff --git a/core/src/avm2/object/vertex_buffer_3d_object.rs b/core/src/avm2/object/vertex_buffer_3d_object.rs index c50a991b4654..d734d69d3b17 100644 --- a/core/src/avm2/object/vertex_buffer_3d_object.rs +++ b/core/src/avm2/object/vertex_buffer_3d_object.rs @@ -3,8 +3,8 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, TObject}; -use crate::utils::HasPrefixField; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::VertexBuffer; use std::rc::Rc; diff --git a/core/src/avm2/object/worker_domain_object.rs b/core/src/avm2/object/worker_domain_object.rs index c782ce54e4c7..cba9d386ef8f 100644 --- a/core/src/avm2/object/worker_domain_object.rs +++ b/core/src/avm2/object/worker_domain_object.rs @@ -1,9 +1,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::TObject; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; #[derive(Clone, Collect, Copy)] #[collect(no_drop)] diff --git a/core/src/avm2/object/worker_object.rs b/core/src/avm2/object/worker_object.rs index 2398892dab24..4c32398e2cb5 100644 --- a/core/src/avm2/object/worker_object.rs +++ b/core/src/avm2/object/worker_object.rs @@ -1,9 +1,9 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::TObject; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::{Collect, Gc, GcWeak}; +use ruffle_common::utils::HasPrefixField; #[derive(Clone, Collect, Copy)] #[collect(no_drop)] diff --git a/core/src/avm2/object/xml_list_object.rs b/core/src/avm2/object/xml_list_object.rs index 4c1ae9aa0f46..b4adc40eda2e 100644 --- a/core/src/avm2/object/xml_list_object.rs +++ b/core/src/avm2/object/xml_list_object.rs @@ -8,12 +8,12 @@ use crate::avm2::object::{Object, TObject}; use crate::avm2::value::Value; use crate::avm2::{Error, Multiname, Namespace}; use crate::string::AvmString; -use crate::utils::HasPrefixField; use gc_arena::barrier::unlock; use gc_arena::{ lock::{Lock, RefLock}, Collect, Gc, GcWeak, Mutation, }; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use ruffle_wstr::WString; use std::cell::{Cell, Ref, RefMut}; diff --git a/core/src/avm2/object/xml_object.rs b/core/src/avm2/object/xml_object.rs index 1d5c45b6404b..5c0605a2c1bc 100644 --- a/core/src/avm2/object/xml_object.rs +++ b/core/src/avm2/object/xml_object.rs @@ -10,10 +10,10 @@ use crate::avm2::object::{ClassObject, NamespaceObject, Object, TObject, XmlList use crate::avm2::string::AvmString; use crate::avm2::value::Value; use crate::avm2::{Error, Multiname}; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::{lock::Lock, Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_wstr::WString; use super::xml_list_object::{E4XOrXml, XmlOrXmlListObject}; diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index 9aad853f430b..3d50b60fc0eb 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -3,12 +3,12 @@ use std::any::Any; use crate::{ avm1::{NativeObject, Object as Avm1Object}, avm2::{Avm2, EventObject as Avm2EventObject, SoundChannelObject}, - buffer::Substream, context::UpdateContext, display_object::{self, DisplayObject, MovieClip, TDisplayObject}, string::AvmString, }; use gc_arena::Collect; +pub use ruffle_common::buffer::Substream; use slotmap::{new_key_type, Key, SlotMap}; #[cfg(feature = "audio")] diff --git a/core/src/backend/audio/decoders.rs b/core/src/backend/audio/decoders.rs index c49e94ff5fbe..628e65fc7469 100644 --- a/core/src/backend/audio/decoders.rs +++ b/core/src/backend/audio/decoders.rs @@ -17,8 +17,8 @@ pub use nellymoser::NellymoserDecoder; pub use pcm::PcmDecoder; use crate::backend::audio::{SoundStreamInfo, SoundStreamWrapping}; -use crate::buffer::{Slice, Substream, SubstreamChunksIter}; use crate::tag_utils::{ControlFlow, SwfSlice}; +use ruffle_common::buffer::{Slice, Substream, SubstreamChunksIter}; use std::io::{Cursor, Read}; use swf::{AudioCompression, SoundFormat, TagCode}; use thiserror::Error; diff --git a/core/src/backend/audio/decoders/adpcm.rs b/core/src/backend/audio/decoders/adpcm.rs index 708d4a0ed961..4e6ca6e26d8a 100644 --- a/core/src/backend/audio/decoders/adpcm.rs +++ b/core/src/backend/audio/decoders/adpcm.rs @@ -1,6 +1,6 @@ use super::{Decoder, SeekableDecoder, SoundStreamInfo, Substream, SubstreamTagReader}; -use crate::buffer::SliceCursor; use bitstream_io::{BigEndian, BitRead, BitReader}; +use ruffle_common::buffer::SliceCursor; use std::io::{Cursor, Read}; use swf::SoundFormat; use thiserror::Error; diff --git a/core/src/backend/audio/mixer.rs b/core/src/backend/audio/mixer.rs index 2aec835c331c..259e6a7898bc 100644 --- a/core/src/backend/audio/mixer.rs +++ b/core/src/backend/audio/mixer.rs @@ -1,8 +1,8 @@ use super::decoders::{self, AdpcmDecoder, Decoder, PcmDecoder, SeekableDecoder}; use super::{SoundHandle, SoundInstanceHandle, SoundStreamInfo, SoundTransform}; use crate::backend::audio::{DecodeError, RegisterError}; -use crate::buffer::Substream; use crate::tag_utils::SwfSlice; +use ruffle_common::buffer::Substream; use slotmap::SlotMap; use std::io::Cursor; use std::sync::{Arc, Mutex, RwLock}; @@ -1099,7 +1099,7 @@ macro_rules! impl_audio_mixer_backend { #[inline] fn start_substream( &mut self, - stream_data: ruffle_core::buffer::Substream, + stream_data: ruffle_core::backend::audio::Substream, stream_info: &SoundStreamInfo, ) -> Result { self.$mixer.start_substream(stream_data, stream_info) diff --git a/core/src/binary_data.rs b/core/src/binary_data.rs index a570815aeab7..3b9828eff744 100644 --- a/core/src/binary_data.rs +++ b/core/src/binary_data.rs @@ -1,10 +1,17 @@ -use crate::tag_utils::{SwfMovie, SwfSlice}; +use gc_arena::Collect; +use ruffle_common::tag_utils::{SwfMovie, SwfSlice}; use std::sync::Arc; -pub type BinaryData = SwfSlice; +#[derive(Collect, Debug)] +#[collect(require_static)] +pub struct BinaryData(SwfSlice); impl BinaryData { pub fn from_swf_tag(movie: Arc, tag: &swf::DefineBinaryData) -> Self { - SwfSlice::from(movie).to_subslice(tag.data) + Self(SwfSlice::from(movie).to_subslice(tag.data)) + } + + pub fn to_vec(&self) -> Vec { + SwfSlice::as_ref(&self.0).to_vec() } } diff --git a/core/src/display_object/avm1_button.rs b/core/src/display_object/avm1_button.rs index 116b4da911d4..71208d9fcbfa 100644 --- a/core/src/display_object/avm1_button.rs +++ b/core/src/display_object/avm1_button.rs @@ -14,12 +14,12 @@ use crate::events::{ClipEvent, ClipEventResult}; use crate::prelude::*; use crate::string::AvmString; use crate::tag_utils::{SwfMovie, SwfSlice}; -use crate::utils::HasPrefixField; use crate::vminterface::Instantiator; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::{Lock, RefLock}; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use ruffle_render::filters::Filter; use std::cell::{Cell, Ref, RefCell, RefMut}; diff --git a/core/src/display_object/avm2_button.rs b/core/src/display_object/avm2_button.rs index 30ecc76f353c..a5db69b6297d 100644 --- a/core/src/display_object/avm2_button.rs +++ b/core/src/display_object/avm2_button.rs @@ -17,13 +17,13 @@ use crate::events::{ClipEvent, ClipEventResult}; use crate::frame_lifecycle::catchup_display_object_to_frame; use crate::prelude::*; use crate::tag_utils::{SwfMovie, SwfSlice}; -use crate::utils::HasPrefixField; use crate::vminterface::Instantiator; use core::fmt; use either::Either; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::filters::Filter; use std::cell::{Cell, RefCell}; use std::sync::Arc; diff --git a/core/src/display_object/bitmap.rs b/core/src/display_object/bitmap.rs index cafde0eefe10..1bc7c4ada710 100644 --- a/core/src/display_object/bitmap.rs +++ b/core/src/display_object/bitmap.rs @@ -11,12 +11,12 @@ use crate::context::{RenderContext, UpdateContext}; use crate::display_object::{DisplayObjectBase, DisplayObjectPtr, DisplayObjectWeak}; use crate::prelude::*; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use crate::vminterface::Instantiator; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::bitmap::{BitmapFormat, PixelSnapping}; use std::cell::Cell; use std::sync::Arc; diff --git a/core/src/display_object/edit_text.rs b/core/src/display_object/edit_text.rs index 91a557506a1a..e0b9a8e73217 100644 --- a/core/src/display_object/edit_text.rs +++ b/core/src/display_object/edit_text.rs @@ -28,7 +28,6 @@ use crate::html::{ use crate::prelude::*; use crate::string::{utils as string_utils, AvmString, SwfStrExt as _, WStr, WString}; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use crate::vminterface::{AvmObject, Instantiator}; use chrono::DateTime; use chrono::Utc; @@ -36,6 +35,7 @@ use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::{Lock, RefLock}; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use ruffle_render::commands::Command as RenderCommand; use ruffle_render::commands::CommandHandler; diff --git a/core/src/display_object/graphic.rs b/core/src/display_object/graphic.rs index be263fbbbb2b..c4b0e117de9f 100644 --- a/core/src/display_object/graphic.rs +++ b/core/src/display_object/graphic.rs @@ -8,12 +8,12 @@ use crate::drawing::Drawing; use crate::library::MovieLibrarySource; use crate::prelude::*; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use crate::vminterface::Instantiator; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::ShapeHandle; use ruffle_render::commands::CommandHandler; use std::cell::{OnceCell, RefCell, RefMut}; diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index 3ab870b323c3..ca0bf9985064 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -18,11 +18,11 @@ use crate::display_object::{ }; use crate::events::{ClipEvent, ClipEventResult, MouseButton}; use crate::string::AvmString; -use crate::utils::HasPrefixField; use bitflags::bitflags; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::{enum_trait_object, istr}; use std::cell::Cell; use std::fmt::Debug; diff --git a/core/src/display_object/loader_display.rs b/core/src/display_object/loader_display.rs index 2d2c14bfc72a..a15ae17efaa7 100644 --- a/core/src/display_object/loader_display.rs +++ b/core/src/display_object/loader_display.rs @@ -11,11 +11,11 @@ use crate::prelude::*; use crate::display_object::container::ChildContainer; use crate::display_object::interactive::InteractiveObjectBase; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::{Lock, RefLock}; use gc_arena::{Collect, Gc, GcWeak, Mutation}; +use ruffle_common::utils::HasPrefixField; use std::cell::{Ref, RefMut}; use std::sync::Arc; diff --git a/core/src/display_object/morph_shape.rs b/core/src/display_object/morph_shape.rs index c0322efecc46..a60d249ffab9 100644 --- a/core/src/display_object/morph_shape.rs +++ b/core/src/display_object/morph_shape.rs @@ -4,11 +4,11 @@ use crate::display_object::DisplayObjectBase; use crate::library::{Library, MovieLibrarySource}; use crate::prelude::*; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::Lock; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::backend::ShapeHandle; use ruffle_render::commands::CommandHandler; use std::cell::{RefCell, RefMut}; diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 767b1bb1c89f..597ccce8c09f 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -35,14 +35,14 @@ use crate::loader::{self, ContentType}; use crate::prelude::*; use crate::streams::NetStream; use crate::string::{AvmString, SwfStrExt as _, WStr, WString}; -use crate::tag_utils::{self, ControlFlow, DecodeResult, Error, SwfMovie, SwfSlice, SwfStream}; -use crate::utils::HasPrefixField; +use crate::tag_utils::{self, ControlFlow, Error, SwfMovie, SwfSlice, SwfStream}; use crate::vminterface::Instantiator; use bitflags::bitflags; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::{Lock, RefLock}; use gc_arena::{Collect, DynamicRoot, Gc, GcWeak, Mutation, Rootable}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use ruffle_render::perspective_projection::PerspectiveProjection; use smallvec::SmallVec; @@ -3732,7 +3732,7 @@ impl<'gc, 'a> MovieClipShared<'gc> { reader: &mut SwfStream<'a>, tag_len: usize, chunk_limit: &mut ExecutionLimit, - ) -> DecodeResult { + ) -> Result { let start = reader.as_slice(); let id = reader.read_character_id()?; let num_frames = reader.read_u16()?; diff --git a/core/src/display_object/stage.rs b/core/src/display_object/stage.rs index c2b1224398e7..4ee7387fff48 100644 --- a/core/src/display_object/stage.rs +++ b/core/src/display_object/stage.rs @@ -17,11 +17,11 @@ use crate::focus_tracker::FocusTracker; use crate::prelude::*; use crate::string::{FromWStr, WStr}; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use crate::vminterface::Instantiator; use bitflags::bitflags; use gc_arena::barrier::unlock; use gc_arena::{Collect, Gc, Lock, Mutation, RefLock}; +use ruffle_common::utils::HasPrefixField; use ruffle_macros::istr; use ruffle_render::backend::ViewportDimensions; use ruffle_render::commands::CommandHandler; diff --git a/core/src/display_object/text.rs b/core/src/display_object/text.rs index 7f51f0646b01..5ae32636e5d9 100644 --- a/core/src/display_object/text.rs +++ b/core/src/display_object/text.rs @@ -4,12 +4,12 @@ use crate::display_object::DisplayObjectBase; use crate::font::{FontLike, TextRenderSettings}; use crate::prelude::*; use crate::tag_utils::SwfMovie; -use crate::utils::HasPrefixField; use crate::vminterface::Instantiator; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::Lock; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::commands::CommandHandler; use ruffle_render::transform::Transform; use ruffle_wstr::WString; diff --git a/core/src/display_object/video.rs b/core/src/display_object/video.rs index ad833cfa3249..b724804cbf3e 100644 --- a/core/src/display_object/video.rs +++ b/core/src/display_object/video.rs @@ -7,12 +7,12 @@ use crate::display_object::{Avm1TextFieldBinding, DisplayObjectBase, RenderOptio use crate::prelude::*; use crate::streams::NetStream; use crate::tag_utils::{SwfMovie, SwfSlice}; -use crate::utils::HasPrefixField; use crate::vminterface::{AvmObject, Instantiator}; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::{Lock, RefLock}; use gc_arena::{Collect, Gc, Mutation}; +use ruffle_common::utils::HasPrefixField; use ruffle_render::bitmap::{BitmapInfo, PixelSnapping}; use ruffle_render::commands::CommandHandler; use ruffle_render::quality::StageQuality; diff --git a/core/src/lib.rs b/core/src/lib.rs index c7e476144b6c..a2c4efd424b9 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -18,7 +18,6 @@ mod avm2; mod avm_rng; mod binary_data; pub mod bitmap; -pub mod buffer; mod character; pub mod context; pub mod context_menu; @@ -40,7 +39,6 @@ mod orphan_manager; pub mod pixel_bender; mod player; mod prelude; -pub mod sandbox; pub mod socket; mod streams; pub mod string; @@ -48,9 +46,7 @@ mod system_properties; pub mod tag_utils; pub mod timer; mod types; -pub mod utils; mod vminterface; -mod xml; pub mod backend; pub mod compatibility_rules; diff --git a/core/src/loader.rs b/core/src/loader.rs index e8731abf5bc1..5302b94dc221 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -176,7 +176,7 @@ pub enum Error { InvalidDomain(String), #[error("Invalid SWF: {0}")] - InvalidSwf(#[from] crate::tag_utils::Error), + InvalidSwf(#[from] swf::error::Error), #[error("Invalid bitmap")] InvalidBitmap(#[from] ruffle_render::error::Error), diff --git a/core/src/streams.rs b/core/src/streams.rs index 38dafcc9d2f0..c762e292d6f1 100644 --- a/core/src/streams.rs +++ b/core/src/streams.rs @@ -14,7 +14,6 @@ use crate::backend::audio::{ DecodeError, SoundInstanceHandle, SoundStreamInfo, SoundStreamWrapping, }; use crate::backend::navigator::Request; -use crate::buffer::{Buffer, Slice, Substream, SubstreamError}; use crate::context::UpdateContext; use crate::display_object::{MovieClip, TDisplayObject}; use crate::loader::Error; @@ -28,6 +27,7 @@ use flv_rs::{ }; use gc_arena::barrier::unlock; use gc_arena::{Collect, DynamicRoot, Gc, Lock, Mutation, Rootable}; +use ruffle_common::buffer::{Buffer, Slice, Substream, SubstreamError}; use ruffle_macros::istr; use ruffle_render::bitmap::BitmapInfo; use ruffle_video::frame::EncodedFrame; diff --git a/core/src/tag_utils.rs b/core/src/tag_utils.rs index 36a86542825d..0e1a781aa0aa 100644 --- a/core/src/tag_utils.rs +++ b/core/src/tag_utils.rs @@ -1,11 +1,9 @@ -use gc_arena::Collect; -use std::fmt::{Debug, Formatter}; -use std::sync::Arc; -use swf::{CharacterId, Fixed8, HeaderExt, Rectangle, TagCode, Twips}; +//! SWF decoding support + +use swf::{CharacterId, TagCode}; use thiserror::Error; -use url::Url; -use crate::sandbox::SandboxType; +pub use ruffle_common::tag_utils::{SwfMovie, SwfSlice, SwfStream}; #[derive(Error, Debug)] pub enum Error { @@ -40,488 +38,6 @@ pub enum ControlFlow { Continue, } -pub type DecodeResult = Result; -pub type SwfStream<'a> = swf::read::Reader<'a>; - -/// An open, fully parsed SWF movie ready to play back, either in a Player or a -/// MovieClip. -#[derive(Clone, Collect)] -#[collect(require_static)] -pub struct SwfMovie { - /// The SWF header parsed from the data stream. - header: HeaderExt, - - /// Uncompressed SWF data. - data: Vec, - - /// The URL the SWF was downloaded from. - url: String, - - /// The URL that triggered the SWF load. - loader_url: Option, - - /// Any parameters provided when loading this movie (also known as 'flashvars'), - /// as a list of key-value pairs. - parameters: Vec<(String, String)>, - - /// The suggest encoding for this SWF. - encoding: &'static swf::Encoding, - - /// The compressed length of the entire datastream - compressed_len: usize, - - /// Whether this SwfMovie actually represents a loaded movie or fills in for - /// something else, like an loaded image, filler movie, or error state. - is_movie: bool, - - /// Security sandbox type enforced for this movie. - /// - /// It absolutely cannot be changed after constructing - /// the object in order to ensure proper sandboxing. - sandbox_type: SandboxType, -} - -impl SwfMovie { - /// Construct an empty movie. - pub fn empty(swf_version: u8, loader_url: Option) -> Self { - let url = "file:///".to_string(); - let header = HeaderExt::default_with_swf_version(swf_version); - - // TODO What sandbox type should we use here? - let sandbox_type = SandboxType::infer(url.as_str(), &header); - Self { - header, - data: vec![], - url, - loader_url, - parameters: Vec::new(), - encoding: swf::UTF_8, - compressed_len: 0, - is_movie: false, - sandbox_type, - } - } - - /// Construct an empty movie with a fake `compressed_len`. - /// This is used by `Loader` when firing an initial `progress` event: - /// `LoaderInfo.bytesTotal` is set to the actual value, but no data is available, - /// and `LoaderInfo.parameters` is empty. - pub fn fake_with_compressed_len( - swf_version: u8, - loader_url: Option, - compressed_len: usize, - ) -> Self { - let url = "file:///".to_string(); - let header = HeaderExt::default_with_swf_version(swf_version); - - // TODO What sandbox type should we use here? - let sandbox_type = SandboxType::infer(url.as_str(), &header); - Self { - header, - compressed_len, - data: Vec::new(), - url, - loader_url, - parameters: Vec::new(), - encoding: swf::UTF_8, - is_movie: false, - sandbox_type, - } - } - - /// Like `fake_with_compressed_len`, but uses actual data. - /// This is used when loading a Bitmap to expose the underlying content - pub fn fake_with_compressed_data( - swf_version: u8, - loader_url: Option, - compressed_data: Vec, - ) -> Self { - let url = "file:///".to_string(); - let header = HeaderExt::default_with_swf_version(swf_version); - - // TODO What sandbox type should we use here? - let sandbox_type = SandboxType::infer(url.as_str(), &header); - Self { - header, - compressed_len: compressed_data.len(), - data: compressed_data, - url, - loader_url, - parameters: Vec::new(), - encoding: swf::UTF_8, - is_movie: false, - sandbox_type, - } - } - - /// Constructs the error state movie stub in which some attributes have certain - /// error values to signal that no valid file could be loaded. - /// - /// This happens if no file could be loaded or if the loaded content is no valid - /// supported content. - pub fn error_movie(movie_url: String) -> Self { - let header = HeaderExt::default_error_header(); - - // TODO What sandbox type should we use here? - let sandbox_type = SandboxType::infer(movie_url.as_str(), &header); - Self { - header, - data: vec![], - url: movie_url, - loader_url: None, - parameters: Vec::new(), - encoding: swf::UTF_8, - compressed_len: 0, - is_movie: false, - sandbox_type, - } - } - - /// Utility method to construct a movie from a file on disk. - #[cfg(any(unix, windows, target_os = "redox"))] - pub fn from_path>( - path: P, - loader_url: Option, - ) -> Result { - let data = std::fs::read(&path)?; - - let abs_path = path.as_ref().canonicalize()?; - let url = url::Url::from_file_path(abs_path).map_err(|()| Error::InvalidSwfUrl)?; - - Self::from_data(&data, url.into(), loader_url) - } - - /// Construct a movie based on the contents of the SWF datastream. - pub fn from_data( - swf_data: &[u8], - url: String, - loader_url: Option, - ) -> Result { - let compressed_len = swf_data.len(); - let swf_buf = swf::read::decompress_swf(swf_data)?; - let encoding = swf::SwfStr::encoding_for_version(swf_buf.header.version()); - let sandbox_type = SandboxType::infer(url.as_str(), &swf_buf.header); - let mut movie = Self { - header: swf_buf.header, - data: swf_buf.data, - url, - loader_url, - parameters: Vec::new(), - encoding, - compressed_len, - is_movie: true, - sandbox_type, - }; - movie.append_parameters_from_url(); - Ok(movie) - } - - /// Construct a movie based on a loaded image (JPEG, GIF or PNG). - pub fn from_loaded_image(url: String, length: usize) -> Self { - let header = HeaderExt::default_with_uncompressed_len(length as i32); - let sandbox_type = SandboxType::infer(url.as_str(), &header); - let mut movie = Self { - header, - data: vec![], - url, - loader_url: None, - parameters: Vec::new(), - encoding: swf::UTF_8, - compressed_len: length, - is_movie: false, - sandbox_type, - }; - movie.append_parameters_from_url(); - movie - } - - fn append_parameters_from_url(&mut self) { - match Url::parse(&self.url) { - Ok(url) => { - for (key, value) in url.query_pairs() { - self.parameters.push((key.into_owned(), value.into_owned())); - } - } - Err(e) => { - tracing::error!( - "Failed to parse loader URL when extracting query parameters: {}", - e - ); - } - } - } - - pub fn header(&self) -> &HeaderExt { - &self.header - } - - /// Get the version of the SWF. - pub fn version(&self) -> u8 { - self.header.version() - } - - pub fn data(&self) -> &[u8] { - &self.data - } - - /// Returns the suggested string encoding for the given SWF version. - /// For SWF version 6 and higher, this is always UTF-8. - /// For SWF version 5 and lower, this is locale-dependent, - /// and we default to WINDOWS-1252. - pub fn encoding(&self) -> &'static swf::Encoding { - self.encoding - } - - /// The width of the movie in twips. - pub fn width(&self) -> Twips { - self.header.stage_size().width() - } - - /// The height of the movie in twips. - pub fn height(&self) -> Twips { - self.header.stage_size().height() - } - - /// Get the URL this SWF was fetched from. - pub fn url(&self) -> &str { - &self.url - } - - pub fn set_url(&mut self, url: String) { - self.url = url; - } - - /// Get the URL that triggered the fetch of this SWF. - pub fn loader_url(&self) -> Option<&str> { - self.loader_url.as_deref() - } - - pub fn parameters(&self) -> &[(String, String)] { - &self.parameters - } - - pub fn append_parameters(&mut self, params: impl IntoIterator) { - self.parameters.extend(params); - } - - pub fn compressed_len(&self) -> usize { - self.compressed_len - } - - pub fn uncompressed_len(&self) -> i32 { - self.header.uncompressed_len() - } - - pub fn is_action_script_3(&self) -> bool { - self.header.is_action_script_3() - } - - pub fn stage_size(&self) -> &Rectangle { - self.header.stage_size() - } - - pub fn num_frames(&self) -> u16 { - self.header.num_frames() - } - - pub fn frame_rate(&self) -> Fixed8 { - self.header.frame_rate() - } - - pub fn is_movie(&self) -> bool { - self.is_movie - } - - pub fn sandbox_type(&self) -> SandboxType { - self.sandbox_type - } -} - -impl Debug for SwfMovie { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("SwfMovie") - .field("header", &self.header) - .field("data", &self.data.len()) - .field("url", &self.url) - .field("loader_url", &self.loader_url) - .field("parameters", &self.parameters) - .field("encoding", &self.encoding) - .field("compressed_len", &self.compressed_len) - .field("is_movie", &self.is_movie) - .field("sandbox_type", &self.sandbox_type) - .finish() - } -} - -/// A shared-ownership reference to some portion of an SWF datastream. -#[derive(Debug, Clone, Collect)] -#[collect(no_drop)] -pub struct SwfSlice { - pub movie: Arc, - pub start: usize, - pub end: usize, -} - -impl From> for SwfSlice { - fn from(movie: Arc) -> Self { - let end = movie.data().len(); - - Self { - movie, - start: 0, - end, - } - } -} - -impl AsRef<[u8]> for SwfSlice { - #[inline] - fn as_ref(&self) -> &[u8] { - self.data() - } -} - -impl SwfSlice { - /// Creates an empty SwfSlice. - #[inline] - pub fn empty(movie: Arc) -> Self { - Self { - movie, - start: 0, - end: 0, - } - } - - /// Creates an empty SwfSlice of the same movie. - #[inline] - pub fn copy_empty(&self) -> Self { - Self::empty(self.movie.clone()) - } - - /// Construct a new SwfSlice from a regular slice. - /// - /// This function returns None if the given slice is not a subslice of the - /// current slice. - pub fn to_subslice(&self, slice: &[u8]) -> Self { - let self_pval = self.movie.data().as_ptr() as usize; - let slice_pval = slice.as_ptr() as usize; - - if (self_pval + self.start) <= slice_pval && slice_pval < (self_pval + self.end) { - Self { - movie: self.movie.clone(), - start: slice_pval - self_pval, - end: (slice_pval - self_pval) + slice.len(), - } - } else { - self.copy_empty() - } - } - - /// Construct a new SwfSlice from a movie subslice. - /// - /// This function allows subslices outside the current slice to be formed, - /// as long as they are valid subslices of the movie itself. - pub fn to_unbounded_subslice(&self, slice: &[u8]) -> Self { - let self_pval = self.movie.data().as_ptr() as usize; - let self_len = self.movie.data().len(); - let slice_pval = slice.as_ptr() as usize; - - if self_pval <= slice_pval && slice_pval < (self_pval + self_len) { - Self { - movie: self.movie.clone(), - start: slice_pval - self_pval, - end: (slice_pval - self_pval) + slice.len(), - } - } else { - self.copy_empty() - } - } - - /// Construct a new SwfSlice from a Reader and a size. - /// - /// This is intended to allow constructing references to the contents of a - /// given SWF tag. You just need the current reader and the size of the tag - /// you want to reference. - /// - /// The returned slice may or may not be a subslice of the current slice. - /// If the resulting slice would be outside the bounds of the underlying - /// movie, or the given reader refers to a different underlying movie, this - /// function returns an empty slice. - pub fn resize_to_reader(&self, reader: &mut SwfStream<'_>, size: usize) -> Self { - if self.movie.data().as_ptr() as usize <= reader.get_ref().as_ptr() as usize - && (reader.get_ref().as_ptr() as usize) - < self.movie.data().as_ptr() as usize + self.movie.data().len() - { - let outer_offset = - reader.get_ref().as_ptr() as usize - self.movie.data().as_ptr() as usize; - let new_start = outer_offset; - let new_end = outer_offset + size; - - let len = self.movie.data().len(); - - if new_start < len && new_end < len { - Self { - movie: self.movie.clone(), - start: new_start, - end: new_end, - } - } else { - self.copy_empty() - } - } else { - self.copy_empty() - } - } - - /// Construct a new SwfSlice from a start and an end. - /// - /// The start and end values will be relative to the current slice. - /// Furthermore, this function will yield an empty slice if the calculated slice - /// would be invalid (e.g. negative length) or would extend past the end of - /// the current slice. - pub fn to_start_and_end(&self, start: usize, end: usize) -> Self { - let new_start = self.start + start; - let new_end = self.start + end; - - if new_start <= new_end { - if let Some(result) = self.movie.data().get(new_start..new_end) { - self.to_subslice(result) - } else { - self.copy_empty() - } - } else { - self.copy_empty() - } - } - - /// Convert the SwfSlice into a standard data slice. - pub fn data(&self) -> &[u8] { - &self.movie.data()[self.start..self.end] - } - - /// Get the version of the SWF this data comes from. - pub fn version(&self) -> u8 { - self.movie.header().version() - } - - /// Checks if this slice is empty - pub fn is_empty(&self) -> bool { - self.end == self.start - } - - /// Construct a reader for this slice. - /// - /// The `from` parameter is the offset to start reading the slice from. - pub fn read_from(&self, from: u64) -> swf::read::Reader<'_> { - swf::read::Reader::new(&self.data()[from as usize..], self.movie.version()) - } - - /// Get the length of the SwfSlice. - pub fn len(&self) -> usize { - self.end - self.start - } -} - /// Decode tags from a SWF stream reader. /// /// The given `tag_callback` will be called for each decoded tag. It will be @@ -578,3 +94,17 @@ where Ok(true) } + +/// Utility method to construct a movie from a file on disk. +#[cfg(any(unix, windows, target_os = "redox"))] +pub fn movie_from_path>( + path: P, + loader_url: Option, +) -> Result { + let data = std::fs::read(&path)?; + + let abs_path = path.as_ref().canonicalize()?; + let url = url::Url::from_file_path(abs_path).map_err(|()| Error::InvalidSwfUrl)?; + + SwfMovie::from_data(&data, url.into(), loader_url).map_err(Error::InvalidSwf) +} diff --git a/exporter/src/exporter.rs b/exporter/src/exporter.rs index 5701965e4ae1..009778d16e9d 100644 --- a/exporter/src/exporter.rs +++ b/exporter/src/exporter.rs @@ -5,7 +5,7 @@ use std::sync::Mutex; use image::RgbaImage; use ruffle_core::limits::ExecutionLimit; -use ruffle_core::tag_utils::SwfMovie; +use ruffle_core::tag_utils::movie_from_path; use ruffle_core::Player; use ruffle_core::PlayerBuilder; use ruffle_render_wgpu::backend::WgpuRenderBackend; @@ -56,7 +56,7 @@ impl Exporter { } pub fn start_exporting_movie(&self, swf_path: &Path) -> Result { - let movie = SwfMovie::from_path(swf_path, None).map_err(|e| anyhow!(e.to_string()))?; + let movie = movie_from_path(swf_path, None).map_err(|e| anyhow!(e.to_string()))?; let width = self .size diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index 886819c4c1c8..afa6b55a130d 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -6,7 +6,7 @@ use crate::logging::{ScanLogBackend, ThreadLocalScanLogger, LOCAL_LOGGER}; use ruffle_core::backend::navigator::{NullExecutor, NullNavigatorBackend}; use ruffle_core::limits::ExecutionLimit; use ruffle_core::swf::{decompress_swf, parse_swf}; -use ruffle_core::tag_utils::SwfMovie; +use ruffle_core::tag_utils::movie_from_path; use ruffle_core::PlayerBuilder; use sha2::{Digest, Sha256}; use std::io::{stdout, Write}; @@ -17,7 +17,7 @@ use std::time::{Duration, Instant}; fn execute_swf(file: &Path) { let base_path = file.parent().unwrap(); let executor = NullExecutor::new(); - let movie = SwfMovie::from_path(file, None).unwrap(); + let movie = movie_from_path(file, None).unwrap(); let frame_time = 1000.0 / movie.frame_rate().to_f64(); let player = PlayerBuilder::new() .with_log(ScanLogBackend::new())