core: Add DefineBinaryData and SymbolClass connection (Part of #1368)

This commit is contained in:
Tal Hayon 2021-08-11 13:35:43 +03:00 committed by kmeisthax
parent 535b614ee4
commit 7b9049cedf
13 changed files with 138 additions and 23 deletions

View File

@ -7,6 +7,7 @@ use crate::avm2::object::{bytearray_allocator, Object, TObject};
use crate::avm2::string::AvmString;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::character::Character;
use encoding_rs::Encoding;
use encoding_rs::UTF_8;
use gc_arena::{GcCell, MutationContext};
@ -20,6 +21,27 @@ pub fn instance_init<'gc>(
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
activation.super_init(this, &[])?;
let class_object = this
.as_class_object()
.ok_or("Attempted to construct non-instance ByteArray")?;
if let Some((movie, id)) = activation
.context
.library
.avm2_class_registry()
.class_symbol(class_object)
{
if let Some(lib) = activation.context.library.library_for_movie(movie) {
if let Some(Character::BinaryData(binary_data)) = lib.character_by_id(id) {
let mut byte_array = this
.as_bytearray_mut(activation.context.gc_context)
.ok_or_else(|| "Unable to get bytearray storage".to_string())?;
byte_array.clear();
byte_array.write_bytes(binary_data.as_ref())?;
byte_array.set_position(0);
}
}
}
}
Ok(Value::Undefined)

10
core/src/binary_data.rs Normal file
View File

@ -0,0 +1,10 @@
use crate::tag_utils::{SwfMovie, SwfSlice};
use std::sync::Arc;
pub type BinaryData = SwfSlice;
impl BinaryData {
pub fn from_swf_tag(movie: Arc<SwfMovie>, tag: &swf::DefineBinaryData) -> Self {
SwfSlice::from(movie).to_subslice(tag.data).unwrap()
}
}

View File

@ -1,4 +1,5 @@
use crate::backend::audio::SoundHandle;
use crate::binary_data::BinaryData;
use crate::display_object::{
Avm1Button, Avm2Button, Bitmap, EditText, Graphic, MorphShape, MovieClip, Text, Video,
};
@ -19,4 +20,5 @@ pub enum Character<'gc> {
Text(Text<'gc>),
Sound(#[collect(require_static)] SoundHandle),
Video(Video<'gc>),
BinaryData(BinaryData),
}

View File

@ -12,6 +12,7 @@ use crate::backend::ui::MouseCursor;
use bitflags::bitflags;
use crate::avm1::activation::{Activation as Avm1Activation, ActivationIdentifier};
use crate::binary_data::BinaryData;
use crate::character::Character;
use crate::context::{ActionType, RenderContext, UpdateContext};
use crate::display_object::container::{
@ -465,6 +466,10 @@ impl<'gc> MovieClip<'gc> {
tag_len,
)
}
TagCode::DefineBinaryData => self
.0
.write(context.gc_context)
.define_binary_data(context, reader),
_ => Ok(()),
};
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::End);
@ -602,9 +607,14 @@ impl<'gc> MovieClip<'gc> {
if id == 0 {
//TODO: This assumes only the root movie has `SymbolClass` tags.
self.set_avm2_class(activation.context.gc_context, Some(class_object));
} else if let Some(Character::MovieClip(mc)) = library.character_by_id(id) {
mc.set_avm2_class(activation.context.gc_context, Some(class_object));
} else {
match library.character_by_id(id) {
Some(Character::MovieClip(mc)) => mc.set_avm2_class(
activation.context.gc_context,
Some(class_object),
),
Some(Character::BinaryData(_)) => {}
_ => {
log::warn!(
"Symbol class {} cannot be assigned to invalid character id {}",
class_name,
@ -612,6 +622,8 @@ impl<'gc> MovieClip<'gc> {
);
}
}
}
}
Err(e) => log::warn!(
"Got AVM2 error {} when attempting to assign symbol class {}",
e,
@ -2986,6 +2998,21 @@ impl<'gc, 'a> MovieClipData<'gc> {
Ok(())
}
#[inline]
fn define_binary_data(
&mut self,
context: &mut UpdateContext<'_, 'gc, '_>,
reader: &mut SwfStream<'a>,
) -> DecodeResult {
let tag_data = reader.read_define_binary_data()?;
let binary_data = BinaryData::from_swf_tag(self.movie(), &tag_data);
context
.library
.library_for_movie_mut(self.movie())
.register_character(tag_data.id, Character::BinaryData(binary_data));
Ok(())
}
#[inline]
fn script_limits(&mut self, reader: &mut SwfStream<'a>, avm: &mut Avm1<'gc>) -> DecodeResult {
let max_recursion_depth = reader.read_u16()?;

View File

@ -24,6 +24,7 @@ extern crate num_derive;
#[macro_use]
mod avm1;
mod avm2;
mod binary_data;
pub mod bitmap;
mod bounding_box;
mod character;

View File

@ -363,10 +363,7 @@ impl<'a> Reader<'a> {
TagCode::ShowFrame => Tag::ShowFrame,
TagCode::CsmTextSettings => Tag::CsmTextSettings(tag_reader.read_csm_text_settings()?),
TagCode::DefineBinaryData => {
let id = tag_reader.read_u16()?;
tag_reader.read_u32()?; // Reserved
let data = tag_reader.read_slice_to_end();
Tag::DefineBinaryData { id, data }
Tag::DefineBinaryData(tag_reader.read_define_binary_data()?)
}
TagCode::DefineBits => {
let id = tag_reader.read_u16()?;
@ -2342,6 +2339,13 @@ impl<'a> Reader<'a> {
})
}
pub fn read_define_binary_data(&mut self) -> Result<DefineBinaryData<'a>> {
let id = self.read_u16()?;
self.read_u32()?; // Reserved
let data = self.read_slice_to_end();
Ok(DefineBinaryData { id, data })
}
pub fn read_define_text(&mut self, version: u8) -> Result<Text> {
let id = self.read_character_id()?;
let bounds = self.read_rectangle()?;

View File

@ -41,10 +41,10 @@ pub fn tag_tests() -> Vec<TagTestData> {
),
(
9, // Minimum version not listed in SWF19.
Tag::DefineBinaryData {
Tag::DefineBinaryData(DefineBinaryData {
id: 1,
data: &[84, 101, 115, 116, 105, 110, 103, 33],
},
}),
read_tag_bytes_from_file("tests/swfs/DefineBinaryData.swf", TagCode::DefineBinaryData),
),
(

View File

@ -786,10 +786,7 @@ pub enum Tag<'a> {
Protect(Option<&'a SwfStr>),
CsmTextSettings(CsmTextSettings),
DebugId(DebugId),
DefineBinaryData {
id: CharacterId,
data: &'a [u8],
},
DefineBinaryData(DefineBinaryData<'a>),
DefineBits {
id: CharacterId,
jpeg_data: &'a [u8],
@ -1301,6 +1298,12 @@ pub struct FontInfo<'a> {
pub code_table: Vec<u16>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct DefineBinaryData<'a> {
pub id: CharacterId,
pub data: &'a [u8],
}
#[derive(Clone, Debug, PartialEq)]
pub struct Text {
pub id: CharacterId,

View File

@ -499,12 +499,7 @@ impl<W: Write> Writer<W> {
self.write_u8(0)?; // Reserved (0).
}
Tag::DefineBinaryData { id, data } => {
self.write_tag_header(TagCode::DefineBinaryData, data.len() as u32 + 6)?;
self.write_u16(id)?;
self.write_u32(0)?; // Reserved
self.output.write_all(data)?;
}
Tag::DefineBinaryData(ref binary_data) => self.write_define_binary_data(binary_data)?,
Tag::DefineBits { id, jpeg_data } => {
self.write_tag_header(TagCode::DefineBits, jpeg_data.len() as u32 + 2)?;
@ -2284,6 +2279,14 @@ impl<W: Write> Writer<W> {
Ok(())
}
fn write_define_binary_data(&mut self, binary_data: &DefineBinaryData) -> Result<()> {
self.write_tag_header(TagCode::DefineBinaryData, binary_data.data.len() as u32 + 6)?;
self.write_u16(binary_data.id)?;
self.write_u32(0)?; // Reserved
self.output.write_all(binary_data.data)?;
Ok(())
}
fn write_define_text(&mut self, text: &Text) -> Result<()> {
let mut buf = Vec::new();
{

View File

@ -621,6 +621,7 @@ swf_tests! {
(as3_istypelate_coerce, "avm2/istypelate_coerce", 1),
(as3_class_cast_call, "avm2/class_cast_call", 1),
(as3_class_supercalls_mismatched, "avm2/class_supercalls_mismatched", 1),
(as3_symbol_class_binary_data, "avm2/symbol_class_binary_data", 1),
}
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.

View File

@ -0,0 +1,34 @@
package {
import flash.display.Sprite;
import flash.utils.ByteArray;
public class TestArray extends ByteArray {
public function TestArray() {
}
}
public class TestArray2 extends ByteArray {
public function TestArray2() {
}
}
public class Test extends Sprite {
public function Test()
{
super();
var bytearr:* = new TestArray();
trace("ByteArray = ");
trace(bytearr);
trace("ByteArray Position = ");
trace(bytearr.position);
var bytearr2:* = new TestArray2();
trace("ByteArray2 = ");
trace(bytearr2);
trace("ByteArray2 Position = ");
trace(bytearr.position);
}
}
}

View File

@ -0,0 +1,8 @@
ByteArray =
TestArrayContent
ByteArray Position =
0
ByteArray2 =
TestArray2Content
ByteArray2 Position =
0