From 556d16302ba5917c822068c067990bf2a7e472f9 Mon Sep 17 00:00:00 2001 From: Lv Yitian <535481388@qq.com> Date: Sun, 3 Mar 2024 03:13:31 +0800 Subject: [PATCH] avm2: Implement flash.media.ID3Info (#14916) --- Cargo.lock | 12 +++ core/Cargo.toml | 1 + core/src/avm2/globals.rs | 3 + core/src/avm2/globals/flash/media/ID3Info.as | 12 +++ core/src/avm2/globals/flash/media/Sound.as | 1 + core/src/avm2/globals/flash/media/sound.rs | 37 +++++++ core/src/avm2/globals/globals.as | 1 + core/src/avm2/object/sound_object.rs | 91 ++++++++++++++++++ core/src/loader.rs | 7 +- tests/tests/swfs/avm2/id3_info/output.txt | 8 ++ tests/tests/swfs/avm2/id3_info/test.as | 24 +++++ tests/tests/swfs/avm2/id3_info/test.swf | Bin 0 -> 1145 bytes tests/tests/swfs/avm2/id3_info/test.toml | 1 + tests/tests/swfs/avm2/id3_info/test_audio.mp3 | Bin 0 -> 25731 bytes 14 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 core/src/avm2/globals/flash/media/ID3Info.as create mode 100644 tests/tests/swfs/avm2/id3_info/output.txt create mode 100644 tests/tests/swfs/avm2/id3_info/test.as create mode 100644 tests/tests/swfs/avm2/id3_info/test.swf create mode 100644 tests/tests/swfs/avm2/id3_info/test.toml create mode 100644 tests/tests/swfs/avm2/id3_info/test_audio.mp3 diff --git a/Cargo.lock b/Cargo.lock index 2ca583270..51b6012ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2625,6 +2625,17 @@ dependencies = [ "objc2", ] +[[package]] +name = "id3" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba0a11a3cf6f08d58a5629531bdb4e7c3b8b595e9812a31a7058b1176c4631e" +dependencies = [ + "bitflags 2.4.2", + "byteorder", + "flate2", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -4417,6 +4428,7 @@ dependencies = [ "fnv", "futures", "hashbrown 0.14.3", + "id3", "image", "indexmap", "jpegxr", diff --git a/core/Cargo.toml b/core/Cargo.toml index 04724aed8..739d1edf9 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -65,6 +65,7 @@ enum-map = "2.7.3" ttf-parser = "0.20" num-bigint = "0.4" unic-segment = "0.9.0" +id3 = "1.12.0" [target.'cfg(not(target_family = "wasm"))'.dependencies.futures] version = "0.3.30" diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index fbb671e0a..bf2c2a080 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -175,6 +175,7 @@ pub struct SystemClasses<'gc> { pub avm1movie: ClassObject<'gc>, pub focusevent: ClassObject<'gc>, pub dictionary: ClassObject<'gc>, + pub id3info: ClassObject<'gc>, } impl<'gc> SystemClasses<'gc> { @@ -308,6 +309,7 @@ impl<'gc> SystemClasses<'gc> { avm1movie: object, focusevent: object, dictionary: object, + id3info: object, } } } @@ -811,6 +813,7 @@ fn load_playerglobal<'gc>( ("flash.geom", "Rectangle", rectangle), ("flash.geom", "Transform", transform), ("flash.geom", "ColorTransform", colortransform), + ("flash.media", "ID3Info", id3info), ("flash.media", "SoundChannel", soundchannel), ("flash.media", "SoundTransform", soundtransform), ("flash.media", "Video", video), diff --git a/core/src/avm2/globals/flash/media/ID3Info.as b/core/src/avm2/globals/flash/media/ID3Info.as new file mode 100644 index 000000000..26e1bdf31 --- /dev/null +++ b/core/src/avm2/globals/flash/media/ID3Info.as @@ -0,0 +1,12 @@ +package flash.media { + + public final dynamic class ID3Info { + public var album:String; + public var artist:String; + public var comment:String; + public var genre:String; + public var songName:String; + public var track:String; + public var year:String; + } +} diff --git a/core/src/avm2/globals/flash/media/Sound.as b/core/src/avm2/globals/flash/media/Sound.as index 1aa2ed9e6..fee66c3ad 100644 --- a/core/src/avm2/globals/flash/media/Sound.as +++ b/core/src/avm2/globals/flash/media/Sound.as @@ -17,6 +17,7 @@ package flash.media { public native function get isURLInaccessible():Boolean; public native function get url():String; public native function get length():Number; + public native function get id3():ID3Info; public native function play(startTime:Number = 0, loops:int = 0, sndTransform:SoundTransform = null):SoundChannel; public native function extract(target:ByteArray, length:Number, startPosition:Number = -1):Number; public native function close():void; diff --git a/core/src/avm2/globals/flash/media/sound.rs b/core/src/avm2/globals/flash/media/sound.rs index 098b54a5b..db64e90f6 100644 --- a/core/src/avm2/globals/flash/media/sound.rs +++ b/core/src/avm2/globals/flash/media/sound.rs @@ -4,10 +4,12 @@ use crate::avm2::activation::Activation; use crate::avm2::object::{Object, QueuedPlay, SoundChannelObject, TObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; +use crate::avm2::Avm2; use crate::avm2::Error; use crate::backend::navigator::Request; use crate::character::Character; use crate::display_object::SoundTransform; +use crate::string::AvmString; use crate::{avm2_stub_getter, avm2_stub_method}; use swf::{SoundEvent, SoundInfo}; @@ -280,6 +282,28 @@ pub fn load_compressed_data_from_byte_array<'gc>( Error::RustError(format!("Failed to register sound from bytearray: {e:?}").into()) })?; + let progress_evt = activation + .avm2() + .classes() + .progressevent + .construct( + activation, + &[ + "progress".into(), + false.into(), + false.into(), + bytes.len().into(), + bytes.len().into(), + ], + ) + .map_err(|e| Error::AvmError(AvmString::new_utf8(activation.gc(), e.to_string()).into()))?; + + Avm2::dispatch_event(&mut activation.context, progress_evt, this); + + this.as_sound_object() + .unwrap() + .read_and_call_id3_event(activation, bytes); + this.as_sound_object() .unwrap() .set_sound(&mut activation.context, handle)?; @@ -296,3 +320,16 @@ pub fn load_pcm_from_byte_array<'gc>( avm2_stub_method!(activation, "flash.media.Sound", "loadPCMFromByteArray"); Ok(Value::Undefined) } + +/// Implements `Sound.id3` +pub fn get_id3<'gc>( + _activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(id3) = this.as_sound_object().unwrap().id3() { + Ok(id3.into()) + } else { + Ok(Value::Null) + } +} diff --git a/core/src/avm2/globals/globals.as b/core/src/avm2/globals/globals.as index 27fed2308..9ab88c323 100644 --- a/core/src/avm2/globals/globals.as +++ b/core/src/avm2/globals/globals.as @@ -241,6 +241,7 @@ include "flash/media/H264Profile.as" include "flash/media/Microphone.as" include "flash/media/MicrophoneEnhancedMode.as" include "flash/media/MicrophoneEnhancedOptions.as" +include "flash/media/ID3Info.as" include "flash/media/Sound.as" include "flash/media/SoundCodec.as" include "flash/media/SoundChannel.as" diff --git a/core/src/avm2/object/sound_object.rs b/core/src/avm2/object/sound_object.rs index 3b201face..c5fc4e59a 100644 --- a/core/src/avm2/object/sound_object.rs +++ b/core/src/avm2/object/sound_object.rs @@ -4,12 +4,16 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; +use crate::avm2::Avm2; use crate::avm2::Error; +use crate::avm2::EventObject; use crate::backend::audio::SoundHandle; use crate::context::UpdateContext; use crate::display_object::SoundTransform; +use crate::string::AvmString; use core::fmt; use gc_arena::{Collect, GcCell, GcWeakCell, Mutation}; +use id3::{Tag, TagLike}; use std::cell::{Ref, RefMut}; use swf::SoundInfo; @@ -29,6 +33,7 @@ pub fn sound_allocator<'gc>( sound_data: SoundData::NotLoaded { queued_plays: Vec::new(), }, + id3: None, }, )) .into()) @@ -58,6 +63,9 @@ pub struct SoundObjectData<'gc> { /// The sound this object holds. sound_data: SoundData<'gc>, + + /// ID3Info Object + id3: Option>, } #[derive(Collect)] @@ -129,6 +137,89 @@ impl<'gc> SoundObject<'gc> { } Ok(()) } + + pub fn id3(self) -> Option> { + let this = self.0.read(); + this.id3 + } + + pub fn set_id3(self, mc: &Mutation<'gc>, id3: Option>) { + let mut this = self.0.write(mc); + this.id3 = id3; + } + + pub fn read_and_call_id3_event(self, activation: &mut Activation<'_, 'gc>, bytes: &[u8]) { + let id3 = activation + .avm2() + .classes() + .id3info + .construct(activation, &[]) + .expect("failed to construct ID3Info object"); + let tag = Tag::read_from(bytes); + if let Ok(ref tag) = tag { + if let Some(v) = tag.album() { + id3.set_public_property( + "album", + AvmString::new_utf8(activation.gc(), v).into(), + activation, + ) + .expect("failed set_public_property"); + } + if let Some(v) = tag.artist() { + id3.set_public_property( + "artist", + AvmString::new_utf8(activation.gc(), v).into(), + activation, + ) + .expect("failed set_public_property"); + } + if let Some(v) = tag.comments().next() { + id3.set_public_property( + "comment", + AvmString::new_utf8(activation.gc(), v.text.clone()).into(), + activation, + ) + .expect("failed set_public_property"); + } + if let Some(v) = tag.genre() { + id3.set_public_property( + "genre", + AvmString::new_utf8(activation.gc(), v).into(), + activation, + ) + .expect("failed set_public_property"); + } + if let Some(v) = tag.title() { + id3.set_public_property( + "songName", + AvmString::new_utf8(activation.gc(), v).into(), + activation, + ) + .expect("failed set_public_property"); + } + if let Some(v) = tag.track() { + id3.set_public_property( + "track", + AvmString::new_utf8(activation.gc(), v.to_string()).into(), + activation, + ) + .expect("failed set_public_property"); + } + if let Some(v) = tag.year() { + id3.set_public_property( + "year", + AvmString::new_utf8(activation.gc(), v.to_string()).into(), + activation, + ) + .expect("failed set_public_property"); + } + } + self.set_id3(activation.context.gc_context, Some(id3)); + if tag.is_ok() { + let id3_evt = EventObject::bare_default_event(&mut activation.context, "id3"); + Avm2::dispatch_event(&mut activation.context, id3_evt, self.into()); + } + } } /// Returns `true` if the sound had a valid position, and `false` otherwise diff --git a/core/src/loader.rs b/core/src/loader.rs index 13bb04f47..c509a022c 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1589,11 +1589,16 @@ impl<'gc> Loader<'gc> { Avm2::dispatch_event(&mut activation.context, progress_evt, sound_object); + sound_object + .as_sound_object() + .expect("Not a sound object") + .read_and_call_id3_event(&mut activation, body.as_slice()); + let complete_evt = Avm2EventObject::bare_default_event( &mut activation.context, "complete", ); - Avm2::dispatch_event(uc, complete_evt, sound_object); + Avm2::dispatch_event(&mut activation.context, complete_evt, sound_object); } Err(_err) => { // FIXME: Match the exact error message generated by Flash. diff --git a/tests/tests/swfs/avm2/id3_info/output.txt b/tests/tests/swfs/avm2/id3_info/output.txt new file mode 100644 index 000000000..adf0a2e04 --- /dev/null +++ b/tests/tests/swfs/avm2/id3_info/output.txt @@ -0,0 +1,8 @@ +id3event id3:[object ID3Info] +album:test album +artist:test artist +comment:test comment +genre:test genre +songName:test title +track:5555 +year:9999 diff --git a/tests/tests/swfs/avm2/id3_info/test.as b/tests/tests/swfs/avm2/id3_info/test.as new file mode 100644 index 000000000..f60071602 --- /dev/null +++ b/tests/tests/swfs/avm2/id3_info/test.as @@ -0,0 +1,24 @@ +package +{ + import flash.display.Sprite; + import flash.events.Event; + import flash.media.Sound; + import flash.net.URLRequest; + + public class Main extends Sprite + { + + public function Main() + { + var sound:Sound = new Sound(); + sound.addEventListener(Event.ID3, function(event:Event):void{ + trace("id3event id3:" + sound.id3); + var properties:Array = ["album", "artist", "comment", "genre", "songName", "track", "year"]; + for (var i:String in properties) trace(properties[i]+":"+sound.id3[properties[i]]); + }); + sound.load(new URLRequest("test_audio.mp3")); + } + + } + +} diff --git a/tests/tests/swfs/avm2/id3_info/test.swf b/tests/tests/swfs/avm2/id3_info/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..f886075f7a8eea4573c19e5b4d1bd7ebdd9f6874 GIT binary patch literal 1145 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 fSDsS=y7=(#Dd2#zEFc=q`agfS;h(