diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 8353512d1..c8f0eba93 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -167,6 +167,7 @@ pub struct SystemClasses<'gc> { pub shaderfilter: ClassObject<'gc>, pub statusevent: ClassObject<'gc>, pub contextmenuevent: ClassObject<'gc>, + pub filereference: ClassObject<'gc>, pub font: ClassObject<'gc>, pub textline: ClassObject<'gc>, pub sampledataevent: ClassObject<'gc>, @@ -296,6 +297,7 @@ impl<'gc> SystemClasses<'gc> { shaderfilter: object, statusevent: object, contextmenuevent: object, + filereference: object, font: object, textline: object, sampledataevent: object, @@ -806,6 +808,7 @@ fn load_playerglobal<'gc>( ("flash.media", "SoundTransform", soundtransform), ("flash.media", "Video", video), ("flash.net", "URLVariables", urlvariables), + ("flash.net", "FileReference", filereference), ("flash.utils", "ByteArray", bytearray), ("flash.system", "ApplicationDomain", application_domain), ("flash.text", "Font", font), diff --git a/core/src/avm2/globals/flash/net.rs b/core/src/avm2/globals/flash/net.rs index 4ab8b8b8c..230521dfe 100644 --- a/core/src/avm2/globals/flash/net.rs +++ b/core/src/avm2/globals/flash/net.rs @@ -5,6 +5,7 @@ use crate::avm2::object::TObject; use crate::avm2::{Activation, Error, Object, Value}; pub mod local_connection; +pub mod file_reference; pub mod net_connection; pub mod net_stream; pub mod object_encoding; diff --git a/core/src/avm2/globals/flash/net/FileReference.as b/core/src/avm2/globals/flash/net/FileReference.as index 170d7ad42..155cd4f7c 100644 --- a/core/src/avm2/globals/flash/net/FileReference.as +++ b/core/src/avm2/globals/flash/net/FileReference.as @@ -4,6 +4,7 @@ package flash.net import flash.utils.ByteArray; import __ruffle__.stub_method; + [Ruffle(InstanceAllocator)] public class FileReference extends EventDispatcher { private var _creationDate: Date; diff --git a/core/src/avm2/globals/flash/net/file_reference.rs b/core/src/avm2/globals/flash/net/file_reference.rs new file mode 100644 index 000000000..3f510d4c5 --- /dev/null +++ b/core/src/avm2/globals/flash/net/file_reference.rs @@ -0,0 +1 @@ +pub use crate::avm2::object::file_reference_allocator; \ No newline at end of file diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 24b36558e..6cc546e90 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -40,6 +40,7 @@ mod dispatch_object; mod domain_object; mod error_object; mod event_object; +mod file_reference_object; mod font_object; mod function_object; mod index_buffer_3d_object; @@ -87,6 +88,7 @@ pub use crate::avm2::object::domain_object::{ }; pub use crate::avm2::object::error_object::{error_allocator, ErrorObject, ErrorObjectWeak}; pub use crate::avm2::object::event_object::{event_allocator, EventObject, EventObjectWeak}; +pub use crate::avm2::object::file_reference_object::{file_reference_allocator, FileReferenceObject, FileReferenceObjectWeak}; pub use crate::avm2::object::font_object::{font_allocator, FontObject, FontObjectWeak}; pub use crate::avm2::object::function_object::{ function_allocator, FunctionObject, FunctionObjectWeak, @@ -191,8 +193,9 @@ use crate::font::Font; ResponderObject(ResponderObject<'gc>), ShaderDataObject(ShaderDataObject<'gc>), SocketObject(SocketObject<'gc>), + FileReferenceObject(FileReferenceObject<'gc>), FontObject(FontObject<'gc>), - LocalConnectionObject(LocalConnectionObject<'gc>) + LocalConnectionObject(LocalConnectionObject<'gc>), } )] pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy { @@ -1420,6 +1423,10 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy fn as_local_connection_object(&self) -> Option> { None } + + fn as_file_reference(&self) -> Option> { + None + } } pub enum ObjectPtr {} @@ -1468,6 +1475,7 @@ impl<'gc> Object<'gc> { Self::ResponderObject(o) => WeakObject::ResponderObject(ResponderObjectWeak(GcCell::downgrade(o.0))), Self::ShaderDataObject(o) => WeakObject::ShaderDataObject(ShaderDataObjectWeak(Gc::downgrade(o.0))), Self::SocketObject(o) => WeakObject::SocketObject(SocketObjectWeak(Gc::downgrade(o.0))), + Self::FileReferenceObject(o) => WeakObject::FileReferenceObject(FileReferenceObjectWeak(Gc::downgrade(o.0))), Self::FontObject(o) => WeakObject::FontObject(FontObjectWeak(GcCell::downgrade(o.0))), Self::LocalConnectionObject(o) => WeakObject::LocalConnectionObject(LocalConnectionObjectWeak(GcCell::downgrade(o.0))), } @@ -1528,6 +1536,7 @@ pub enum WeakObject<'gc> { ResponderObject(ResponderObjectWeak<'gc>), ShaderDataObject(ShaderDataObjectWeak<'gc>), SocketObject(SocketObjectWeak<'gc>), + FileReferenceObject(FileReferenceObjectWeak<'gc>), FontObject(FontObjectWeak<'gc>), LocalConnectionObject(LocalConnectionObjectWeak<'gc>), } @@ -1571,6 +1580,7 @@ impl<'gc> WeakObject<'gc> { Self::ResponderObject(o) => ResponderObject(o.0.upgrade(mc)?).into(), Self::ShaderDataObject(o) => ShaderDataObject(o.0.upgrade(mc)?).into(), Self::SocketObject(o) => SocketObject(o.0.upgrade(mc)?).into(), + Self::FileReferenceObject(o) => FileReferenceObject(o.0.upgrade(mc)?).into(), Self::FontObject(o) => FontObject(o.0.upgrade(mc)?).into(), Self::LocalConnectionObject(o) => LocalConnectionObject(o.0.upgrade(mc)?).into(), }) diff --git a/core/src/avm2/object/file_reference_object.rs b/core/src/avm2/object/file_reference_object.rs new file mode 100644 index 000000000..514bbf7f5 --- /dev/null +++ b/core/src/avm2/object/file_reference_object.rs @@ -0,0 +1,68 @@ +use crate::avm2::object::script_object::ScriptObjectData; +use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; +use crate::avm2::value::Value; +use crate::avm2::{Activation, Error}; +use gc_arena::barrier::unlock; +use gc_arena::{lock::RefLock, Collect, Gc}; +use gc_arena::{GcWeak, Mutation}; +use std::cell::{Cell, Ref, RefCell, RefMut}; +use std::fmt; + +pub fn file_reference_allocator<'gc>( + class: ClassObject<'gc>, + activation: &mut Activation<'_, 'gc>, +) -> Result, Error<'gc>> { + let base = ScriptObjectData::new(class).into(); + + Ok(FileReferenceObject(Gc::new( + activation.context.gc(), + FileReferenceObjectData { + base, + }, + )) + .into()) +} + + +#[derive(Clone, Collect, Copy)] +#[collect(no_drop)] +pub struct FileReferenceObject<'gc>(pub Gc<'gc, FileReferenceObjectData<'gc>>); + +#[derive(Clone, Collect, Copy, Debug)] +#[collect(no_drop)] +pub struct FileReferenceObjectWeak<'gc>(pub GcWeak<'gc, FileReferenceObjectData<'gc>>); + +impl<'gc> TObject<'gc> for FileReferenceObject<'gc> { + fn base(&self) -> Ref> { + self.0.base.borrow() + } + + fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut> { + unlock!(Gc::write(mc, self.0), FileReferenceObjectData, base).borrow_mut() + } + + fn as_ptr(&self) -> *const ObjectPtr { + Gc::as_ptr(self.0) as *const ObjectPtr + } + + fn value_of(&self, _mc: &Mutation<'gc>) -> Result, Error<'gc>> { + Ok(Value::Object(Object::from(*self))) + } + + fn as_file_reference(&self) -> Option> { + Some(*self) + } +} + +#[derive(Collect)] +#[collect(no_drop)] +pub struct FileReferenceObjectData<'gc> { + /// Base script object + base: RefLock>, +} + +impl fmt::Debug for FileReferenceObject<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "FileReferenceObject") + } +}