diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 007bb0a51..06bb9be81 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -458,14 +458,6 @@ pub fn load_player_globals<'gc>( ); // package `flash.utils` - avm2_system_class!( - bytearray, - activation, - flash::utils::bytearray::create_class(mc), - script - ); - - domain.init_default_domain_memory(activation)?; class( activation, @@ -722,8 +714,11 @@ fn load_playerglobal<'gc>( ("flash.geom", "Rectangle", rectangle), ("flash.geom", "Transform", transform), ("flash.geom", "ColorTransform", colortransform), + ("flash.utils", "ByteArray", bytearray), ] ); + // Domain memory must be initialized after playerglobals is loaded because it relies on ByteArray. + domain.init_default_domain_memory(activation)?; Ok(()) } diff --git a/core/src/avm2/globals/flash/utils.rs b/core/src/avm2/globals/flash/utils.rs index 264933797..fc479e376 100644 --- a/core/src/avm2/globals/flash/utils.rs +++ b/core/src/avm2/globals/flash/utils.rs @@ -8,7 +8,7 @@ use crate::string::WString; use instant::Instant; use std::fmt::Write; -pub mod bytearray; +pub mod byte_array; pub mod dictionary; pub mod proxy; pub mod timer; diff --git a/core/src/avm2/globals/flash/utils/ByteArray.as b/core/src/avm2/globals/flash/utils/ByteArray.as index 5ebb909d9..d3fb96da2 100644 --- a/core/src/avm2/globals/flash/utils/ByteArray.as +++ b/core/src/avm2/globals/flash/utils/ByteArray.as @@ -1,5 +1,72 @@ -// This is a stub - the actual class is defined in `bytearray.rs` package flash.utils { + [Ruffle(InstanceAllocator)] public class ByteArray { + private static var _defaultObjectEncoding:uint = 3; + public static function get defaultObjectEncoding():uint { + return _defaultObjectEncoding; + } + + public static function set defaultObjectEncoding(encoding:uint):void { + _defaultObjectEncoding = encoding; + } + + public native function get bytesAvailable():uint; + + public native function get endian():String; + public native function set endian(value:String):void; + + public native function get length():uint; + public native function set length(value:uint):void; + + public native function get objectEncoding():uint; + public native function set objectEncoding(value:uint):void; + + public native function get position():uint; + public native function set position(value:uint):void; + + public function ByteArray() { + this.init(); + this.objectEncoding = _defaultObjectEncoding; + } + + private native function init():void; + + public native function clear():void; + public native function compress(algorithm:String):void; + public native function deflate():void; + public native function inflate():void; + public native function uncompress(algorithm:String):void; + + public native function toString():String; + public function toJSON(k:String):String { + return "ByteArray" + } + + public native function readBoolean():Boolean; + public native function readByte():int; + public native function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void; + public native function readDouble():Number; + public native function readFloat():Number; + public native function readInt():int; + public native function readMultiByte(length:uint, charSet:String):String; + public native function readObject():*; + public native function readShort():int; + public native function readUnsignedByte():uint; + public native function readUnsignedInt():uint; + public native function readUnsignedShort():uint; + public native function readUTF():String; + public native function readUTFBytes(length:uint):String; + + public native function writeBoolean(value:Boolean):void; + public native function writeByte(value:int):void; + public native function writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void; + public native function writeDouble(value:Number):void; + public native function writeFloat(value:Number):void; + public native function writeInt(value:int):void; + public native function writeMultiByte(value:String, charSet:String):void; + public native function writeShort(value:int):void; + public native function writeUnsignedInt(value:uint):void; + public native function writeUTF(value:String):void; + public native function writeUTFBytes(value:String):void; } } diff --git a/core/src/avm2/globals/flash/utils/bytearray.rs b/core/src/avm2/globals/flash/utils/byte_array.rs similarity index 88% rename from core/src/avm2/globals/flash/utils/bytearray.rs rename to core/src/avm2/globals/flash/utils/byte_array.rs index 4cb64608b..0c5ca9c94 100644 --- a/core/src/avm2/globals/flash/utils/bytearray.rs +++ b/core/src/avm2/globals/flash/utils/byte_array.rs @@ -1,23 +1,18 @@ use crate::avm2::activation::Activation; use crate::avm2::bytearray::{CompressionAlgorithm, Endian, ObjectEncoding}; -use crate::avm2::class::{Class, ClassAttributes}; -use crate::avm2::method::{Method, NativeMethodImpl}; -use crate::avm2::object::{bytearray_allocator, Object, TObject}; +pub use crate::avm2::object::byte_array_allocator; +use crate::avm2::object::{Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::avm2::Multiname; -use crate::avm2::Namespace; -use crate::avm2::QName; use crate::character::Character; use crate::string::AvmString; use encoding_rs::Encoding; use encoding_rs::UTF_8; use flash_lso::amf0::read::AMF0Decoder; use flash_lso::amf3::read::AMF3Decoder; -use gc_arena::{GcCell, MutationContext}; /// Implements `flash.utils.ByteArray`'s instance constructor. -pub fn instance_init<'gc>( +pub fn init<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Option>, _args: &[Value<'gc>], @@ -50,15 +45,6 @@ pub fn instance_init<'gc>( Ok(Value::Undefined) } -/// Implements `flash.utils.ByteArray`'s class constructor. -pub fn class_init<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Option>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - Ok(Value::Undefined) -} - /// Writes a single byte to the bytearray pub fn write_byte<'gc>( activation: &mut Activation<'_, 'gc, '_>, @@ -251,7 +237,7 @@ pub fn clear<'gc>( Ok(Value::Undefined) } -pub fn position<'gc>( +pub fn get_position<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Option>, _args: &[Value<'gc>], @@ -283,7 +269,7 @@ pub fn set_position<'gc>( Ok(Value::Undefined) } -pub fn bytes_available<'gc>( +pub fn get_bytes_available<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Option>, _args: &[Value<'gc>], @@ -297,7 +283,7 @@ pub fn bytes_available<'gc>( Ok(Value::Undefined) } -pub fn length<'gc>( +pub fn get_length<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Option>, _args: &[Value<'gc>], @@ -329,7 +315,7 @@ pub fn set_length<'gc>( Ok(Value::Undefined) } -pub fn endian<'gc>( +pub fn get_endian<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Option>, _args: &[Value<'gc>], @@ -623,7 +609,7 @@ pub fn write_short<'gc>( Ok(Value::Undefined) } -pub fn write_multibyte<'gc>( +pub fn write_multi_byte<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Option>, args: &[Value<'gc>], @@ -649,7 +635,7 @@ pub fn write_multibyte<'gc>( Ok(Value::Undefined) } -pub fn read_multibyte<'gc>( +pub fn read_multi_byte<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Option>, args: &[Value<'gc>], @@ -804,7 +790,7 @@ pub fn read_object<'gc>( Ok(Value::Undefined) } -pub fn object_encoding<'gc>( +pub fn get_object_encoding<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Option>, _args: &[Value<'gc>], @@ -839,77 +825,3 @@ pub fn set_object_encoding<'gc>( Ok(Value::Undefined) } - -pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { - let class = Class::new( - QName::new(Namespace::package("flash.utils"), "ByteArray"), - Some(Multiname::public("Object")), - Method::from_builtin(instance_init, "", mc), - Method::from_builtin(class_init, "", mc), - mc, - ); - - let mut write = class.write(mc); - - write.set_attributes(ClassAttributes::SEALED); - write.set_instance_allocator(bytearray_allocator); - - const PUBLIC_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] = &[ - ("writeByte", write_byte), - ("writeBytes", write_bytes), - ("readBytes", read_bytes), - ("toString", to_string), - ("readShort", read_short), - ("writeShort", write_short), - ("readUnsignedShort", read_unsigned_short), - ("readDouble", read_double), - ("writeDouble", write_double), - ("readFloat", read_float), - ("writeFloat", write_float), - ("readInt", read_int), - ("writeInt", write_int), - ("readUnsignedInt", read_unsigned_int), - ("writeUnsignedInt", write_unsigned_int), - ("readBoolean", read_boolean), - ("writeBoolean", write_boolean), - ("readByte", read_byte), - ("readUnsignedByte", read_unsigned_byte), - ("writeUTF", write_utf), - ("readUTF", read_utf), - ("clear", clear), - ("compress", compress), - ("uncompress", uncompress), - ("inflate", inflate), - ("deflate", deflate), - ("writeMultiByte", write_multibyte), - ("readMultiByte", read_multibyte), - ("writeUTFBytes", write_utf_bytes), - ("readUTFBytes", read_utf_bytes), - ("readObject", read_object), - ]; - write.define_public_builtin_instance_methods(mc, PUBLIC_INSTANCE_METHODS); - - const PUBLIC_INSTANCE_PROPERTIES: &[( - &str, - Option, - Option, - )] = &[ - ("bytesAvailable", Some(bytes_available), None), - ("length", Some(length), Some(set_length)), - ("position", Some(position), Some(set_position)), - ("endian", Some(endian), Some(set_endian)), - ( - "objectEncoding", - Some(object_encoding), - Some(set_object_encoding), - ), - ]; - write.define_public_builtin_instance_properties(mc, PUBLIC_INSTANCE_PROPERTIES); - - // TODO: This property should have a setter - const CONSTANTS: &[(&str, u32)] = &[("defaultObjectEncoding", 3)]; - - write.define_public_constant_uint_class_traits(CONSTANTS); - - class -} diff --git a/core/src/avm2/globals/globals.as b/core/src/avm2/globals/globals.as index b2d034a11..c7e5ff15b 100644 --- a/core/src/avm2/globals/globals.as +++ b/core/src/avm2/globals/globals.as @@ -6,6 +6,7 @@ include "Math.as" include "flash/accessibility/AccessibilityProperties.as" include "flash/crypto.as" +include "flash/utils/ByteArray.as" include "flash/desktop/ClipboardFormats.as" include "flash/desktop/ClipboardTransferMode.as" include "flash/display/ActionScriptVersion.as" @@ -174,4 +175,4 @@ include "flash/ui/MultitouchInputMode.as" include "flash/utils.as" include "flash/utils/CompressionAlgorithm.as" include "flash/utils/Endian.as" -include "flash/utils/Timer.as" +include "flash/utils/Timer.as" \ No newline at end of file diff --git a/core/src/avm2/globals/stubs.as b/core/src/avm2/globals/stubs.as index 555be57fa..fa822610f 100644 --- a/core/src/avm2/globals/stubs.as +++ b/core/src/avm2/globals/stubs.as @@ -16,7 +16,6 @@ include "flash/display/DisplayObjectContainer.as" include "flash/display/LoaderInfo.as" include "flash/events/EventDispatcher.as" include "flash/system/ApplicationDomain.as" -include "flash/utils/ByteArray.as" include "flash/utils/Dictionary.as" include "Function.as" include "Number.as" diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 71b787232..bc237841d 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -54,7 +54,7 @@ mod xml_object; pub use crate::avm2::object::array_object::{array_allocator, ArrayObject}; pub use crate::avm2::object::bitmapdata_object::{bitmapdata_allocator, BitmapDataObject}; -pub use crate::avm2::object::bytearray_object::{bytearray_allocator, ByteArrayObject}; +pub use crate::avm2::object::bytearray_object::{byte_array_allocator, ByteArrayObject}; pub use crate::avm2::object::class_object::ClassObject; pub use crate::avm2::object::date_object::{date_allocator, DateObject}; pub use crate::avm2::object::dictionary_object::{dictionary_allocator, DictionaryObject}; diff --git a/core/src/avm2/object/bytearray_object.rs b/core/src/avm2/object/bytearray_object.rs index a0d6e7311..53046b796 100644 --- a/core/src/avm2/object/bytearray_object.rs +++ b/core/src/avm2/object/bytearray_object.rs @@ -9,7 +9,7 @@ use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::{Ref, RefMut}; /// A class instance allocator that allocates ByteArray objects. -pub fn bytearray_allocator<'gc>( +pub fn byte_array_allocator<'gc>( class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc, '_>, ) -> Result, Error<'gc>> { diff --git a/tests/tests/swfs/avm2/bytearray_readobject_amf0/Test.as b/tests/tests/swfs/avm2/bytearray_readobject_amf0/Test.as index b7f816e32..cd67aeddf 100644 --- a/tests/tests/swfs/avm2/bytearray_readobject_amf0/Test.as +++ b/tests/tests/swfs/avm2/bytearray_readobject_amf0/Test.as @@ -24,7 +24,6 @@ public function testToObject(arr) { var ba = new ByteArray(); - ba.objectEncoding = "AMF0"; for (var i = 0; i < arr.length; i++) { ba.writeByte(arr[i]); @@ -34,6 +33,7 @@ } public function Test() { + ByteArray.defaultObjectEncoding = 0; for (var i = 0; i < TESTS.length; i++) { var obj = testToObject(TESTS[i]); diff --git a/tests/tests/swfs/avm2/bytearray_readobject_amf0/test.swf b/tests/tests/swfs/avm2/bytearray_readobject_amf0/test.swf index c2c813500..b9fa93c43 100644 Binary files a/tests/tests/swfs/avm2/bytearray_readobject_amf0/test.swf and b/tests/tests/swfs/avm2/bytearray_readobject_amf0/test.swf differ