From 4285d998dc5f37753748b65eed6179b26aec6229 Mon Sep 17 00:00:00 2001 From: sleepycatcoding <131554884+sleepycatcoding@users.noreply.github.com> Date: Tue, 19 Sep 2023 17:05:29 +0300 Subject: [PATCH] avm2: Add target property to XMLListObject --- core/src/avm2/activation.rs | 6 ++-- core/src/avm2/globals/xml.rs | 45 ++++++++++++++++++------ core/src/avm2/globals/xml_list.rs | 31 +++++++++++++---- core/src/avm2/multiname.rs | 10 ++++++ core/src/avm2/object/xml_list_object.rs | 46 +++++++++++++++++-------- core/src/avm2/object/xml_object.rs | 14 ++++---- 6 files changed, 111 insertions(+), 41 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 0fca1b29e..bec11d93c 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -2140,7 +2140,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { ) => { let mut children = value1.children().clone(); children.push(E4XOrXml::Xml(value2)); - XmlListObject::new(self, children, None).into() + XmlListObject::new(self, children, None, None).into() } ( Value::Object(Object::XmlObject(value1)), @@ -2148,14 +2148,14 @@ impl<'a, 'gc> Activation<'a, 'gc> { ) => { let mut children = vec![E4XOrXml::Xml(value1)]; children.extend(value2.children().clone()); - XmlListObject::new(self, children, None).into() + XmlListObject::new(self, children, None, None).into() } ( Value::Object(Object::XmlObject(value1)), Value::Object(Object::XmlObject(value2)), ) => { let children = vec![E4XOrXml::Xml(value1), E4XOrXml::Xml(value2)]; - XmlListObject::new(self, children, None).into() + XmlListObject::new(self, children, None, None).into() } (value1, value2) => { let prim_value1 = value1.coerce_to_primitive(None, self)?; diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index 6b2846d1a..4d064c311 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -224,7 +224,7 @@ pub fn child<'gc>( } else { Vec::new() }; - return Ok(XmlListObject::new(activation, children, None).into()); + return Ok(XmlListObject::new(activation, children, None, None).into()); } } @@ -237,7 +237,8 @@ pub fn child<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, children, Some(xml.into())).into()) + // FIXME: If name is not a number index, then we should call [[Get]] (get_property_local) with the name. + Ok(XmlListObject::new(activation, children, Some(xml.into()), Some(multiname)).into()) } pub fn child_index<'gc>( @@ -281,7 +282,14 @@ pub fn children<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, children, Some(xml.into())).into()) + // FIXME: Spec says to just call [[Get]] with * (any multiname). + Ok(XmlListObject::new( + activation, + children, + Some(xml.into()), + Some(Multiname::any(activation.gc())), + ) + .into()) } pub fn copy<'gc>( @@ -329,7 +337,7 @@ pub fn elements<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, children, Some(xml.into())).into()) + Ok(XmlListObject::new(activation, children, Some(xml.into()), None).into()) } pub fn attributes<'gc>( @@ -344,7 +352,14 @@ pub fn attributes<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, attributes, Some(xml.into())).into()) + // FIXME: Spec/avmplus says to call [[Get]] with * attribute name (any attribute multiname). + Ok(XmlListObject::new( + activation, + attributes, + Some(xml.into()), + Some(Multiname::any_attribute(activation.gc())), + ) + .into()) } pub fn attribute<'gc>( @@ -364,7 +379,8 @@ pub fn attribute<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, attributes, Some(xml.into())).into()) + // FIXME: Spec/avmplus call [[Get]] with attribute name. + Ok(XmlListObject::new(activation, attributes, Some(xml.into()), Some(multiname)).into()) } pub fn call_handler<'gc>( @@ -510,9 +526,10 @@ pub fn descendants<'gc>( let multiname = name_to_multiname(activation, &args[0], false)?; let mut descendants = Vec::new(); xml.node().descendants(&multiname, &mut descendants); - Ok(XmlListObject::new(activation, descendants, Some(xml.into())).into()) + Ok(XmlListObject::new(activation, descendants, None, None).into()) } +// ECMA-357 13.4.4.37 XML.prototype.text ( ) pub fn text<'gc>( activation: &mut Activation<'_, 'gc>, this: Object<'gc>, @@ -528,7 +545,9 @@ pub fn text<'gc>( } else { Vec::new() }; - Ok(XmlListObject::new(activation, nodes, Some(xml.into())).into()) + // 1. Let list be a new XMLList with list.[[TargetObject]] = x and list.[[TargetProperty]] = null + // 3. Return list + Ok(XmlListObject::new(activation, nodes, Some(xml.into()), None).into()) } pub fn length<'gc>( @@ -559,6 +578,7 @@ pub fn has_simple_content<'gc>( Ok(result.into()) } +// ECMA-357 13.4.4.9 XML.prototype.comments ( ) pub fn comments<'gc>( activation: &mut Activation<'_, 'gc>, this: Object<'gc>, @@ -575,9 +595,12 @@ pub fn comments<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, comments, Some(xml.into())).into()) + // 1. Let list be a new XMLList with list.[[TargetObject]] = x and list.[[TargetProperty]] = null + // 3. Return list + Ok(XmlListObject::new(activation, comments, Some(xml.into()), None).into()) } +// ECMA-357 13.4.4.28 XML.prototype.processingInstructions ( [ name ] ) pub fn processing_instructions<'gc>( activation: &mut Activation<'_, 'gc>, this: Object<'gc>, @@ -598,7 +621,9 @@ pub fn processing_instructions<'gc>( Vec::new() }; - Ok(XmlListObject::new(activation, nodes, Some(xml.into())).into()) + // 3. Let list = a new XMLList with list.[[TargetObject]] = x and list.[[TargetProperty]] = null + // 5. Return list + Ok(XmlListObject::new(activation, nodes, Some(xml.into()), None).into()) } // ECMA-357 13.4.4.18 XML.prototype.insertChildAfter (child1, child2) diff --git a/core/src/avm2/globals/xml_list.rs b/core/src/avm2/globals/xml_list.rs index 3e595126d..d34b17abd 100644 --- a/core/src/avm2/globals/xml_list.rs +++ b/core/src/avm2/globals/xml_list.rs @@ -6,6 +6,7 @@ pub use crate::avm2::object::xml_list_allocator; use crate::avm2::{ e4x::{name_to_multiname, simple_content_to_string, E4XNode, E4XNodeKind}, error::type_error, + multiname::Multiname, object::{E4XOrXml, XmlListObject}, parameters::ParametersExt, string::AvmString, @@ -176,7 +177,7 @@ pub fn child<'gc>( ); } } - Ok(XmlListObject::new(activation, sub_children, Some(list.into())).into()) + Ok(XmlListObject::new(activation, sub_children, Some(list.into()), None).into()) } pub fn children<'gc>( @@ -192,7 +193,14 @@ pub fn children<'gc>( sub_children.extend(children.iter().map(|node| E4XOrXml::E4X(*node))); } } - Ok(XmlListObject::new(activation, sub_children, Some(list.into())).into()) + // FIXME: This method should just call get_property_local with "*". + Ok(XmlListObject::new( + activation, + sub_children, + Some(list.into()), + Some(Multiname::any(activation.gc())), + ) + .into()) } pub fn copy<'gc>( @@ -227,7 +235,9 @@ pub fn attribute<'gc>( } } } - Ok(XmlListObject::new(activation, sub_children, Some(list.into())).into()) + + // FIXME: This should just use get_property_local with an attribute Multiname. + Ok(XmlListObject::new(activation, sub_children, Some(list.into()), Some(multiname)).into()) } pub fn attributes<'gc>( @@ -244,7 +254,14 @@ pub fn attributes<'gc>( } } - Ok(XmlListObject::new(activation, child_attrs, Some(list.into())).into()) + // FIXME: This should just use get_property_local with an any attribute Multiname. + Ok(XmlListObject::new( + activation, + child_attrs, + Some(list.into()), + Some(Multiname::any_attribute(activation.gc())), + ) + .into()) } pub fn name<'gc>( @@ -299,7 +316,7 @@ pub fn text<'gc>( ); } } - Ok(XmlListObject::new(activation, nodes, Some(xml_list.into())).into()) + Ok(XmlListObject::new(activation, nodes, Some(xml_list.into()), None).into()) } pub fn comments<'gc>( @@ -319,7 +336,7 @@ pub fn comments<'gc>( ); } } - Ok(XmlListObject::new(activation, nodes, Some(xml_list.into())).into()) + Ok(XmlListObject::new(activation, nodes, Some(xml_list.into()), None).into()) } pub fn processing_instructions<'gc>( @@ -344,5 +361,5 @@ pub fn processing_instructions<'gc>( } } - Ok(XmlListObject::new(activation, nodes, Some(xml_list.into())).into()) + Ok(XmlListObject::new(activation, nodes, Some(xml_list.into()), None).into()) } diff --git a/core/src/avm2/multiname.rs b/core/src/avm2/multiname.rs index 170d23f56..981815812 100644 --- a/core/src/avm2/multiname.rs +++ b/core/src/avm2/multiname.rs @@ -310,6 +310,16 @@ impl<'gc> Multiname<'gc> { } } + /// Indicates the any attribute type (any attribute in any namespace). + pub fn any_attribute(mc: &Mutation<'gc>) -> Self { + Self { + ns: NamespaceSet::single(Namespace::any(mc)), + name: None, + param: None, + flags: MultinameFlags::ATTRIBUTE, + } + } + pub fn new(ns: Namespace<'gc>, name: impl Into>) -> Self { Self { ns: NamespaceSet::single(ns), diff --git a/core/src/avm2/object/xml_list_object.rs b/core/src/avm2/object/xml_list_object.rs index c4961bbb4..38150f16c 100644 --- a/core/src/avm2/object/xml_list_object.rs +++ b/core/src/avm2/object/xml_list_object.rs @@ -26,7 +26,8 @@ pub fn xml_list_allocator<'gc>( children: Vec::new(), // An XMLList created by 'new XMLList()' is not linked // to any object - target: None, + target_object: None, + target_property: None, }, )) .into()) @@ -52,7 +53,8 @@ impl<'gc> XmlListObject<'gc> { pub fn new( activation: &mut Activation<'_, 'gc>, children: Vec>, - target: Option>, + target_object: Option>, + target_property: Option>, ) -> Self { let base = ScriptObjectData::new(activation.context.avm2.classes().xml_list); XmlListObject(GcCell::new( @@ -60,7 +62,8 @@ impl<'gc> XmlListObject<'gc> { XmlListObjectData { base, children, - target, + target_object, + target_property, }, )) } @@ -94,8 +97,12 @@ impl<'gc> XmlListObject<'gc> { self.0.write(mc).children = children; } - pub fn target(&self) -> Option> { - self.0.read().target + pub fn target_object(&self) -> Option> { + self.0.read().target_object + } + + pub fn target_property(&self) -> Option> { + self.0.read().target_property.clone() } pub fn deep_copy(&self, activation: &mut Activation<'_, 'gc>) -> XmlListObject<'gc> { @@ -104,7 +111,12 @@ impl<'gc> XmlListObject<'gc> { .iter() .map(|child| E4XOrXml::E4X(child.node().deep_copy(activation.context.gc_context))) .collect(); - XmlListObject::new(activation, children, self.target()) + XmlListObject::new( + activation, + children, + self.target_object(), + self.target_property(), + ) } pub fn equals( @@ -160,7 +172,7 @@ impl<'gc> XmlListObject<'gc> { let mut out = vec![]; out.extend(left.children().clone()); out.extend(right.children().clone()); - Self::new(activation, out, None) + Self::new(activation, out, None, None) } } } @@ -177,7 +189,9 @@ pub struct XmlListObjectData<'gc> { /// The XML or XMLList object that this list was created from. /// If `Some`, then modifications to this list are reflected /// in the original object. - target: Option>, + target_object: Option>, + + target_property: Option>, } /// Holds either an `E4XNode` or an `XmlObject`. This can be converted @@ -260,11 +274,7 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> { for child in self.0.read().children.iter() { child.node().descendants(multiname, &mut descendants); } - Some(XmlListObject::new( - activation, - descendants, - Some((*self).into()), - )) + Some(XmlListObject::new(activation, descendants, None, None)) } fn get_property_local( @@ -309,7 +319,13 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> { }) .collect(); - Ok(XmlListObject::new(activation, matched_children, Some(self.into())).into()) + Ok(XmlListObject::new( + activation, + matched_children, + Some(self.into()), + Some(name.clone()), + ) + .into()) } fn call_property_local( @@ -377,7 +393,7 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> { if let Some(local_name) = name.local_name() { if let Ok(index) = local_name.parse::() { // 2.a. If x.[[TargetObject]] is not null - if let Some(target) = write.target { + if let Some(target) = write.target_object { return Err(format!( "Modifying an XMLList object is not yet implemented: target {:?}", target diff --git a/core/src/avm2/object/xml_object.rs b/core/src/avm2/object/xml_object.rs index 35098e783..b5f230c96 100644 --- a/core/src/avm2/object/xml_object.rs +++ b/core/src/avm2/object/xml_object.rs @@ -183,11 +183,7 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> { ) -> Option> { let mut descendants = Vec::new(); self.0.read().node.descendants(multiname, &mut descendants); - Some(XmlListObject::new( - activation, - descendants, - Some((*self).into()), - )) + Some(XmlListObject::new(activation, descendants, None, None)) } fn get_property_local( @@ -236,7 +232,13 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> { Vec::new() }; - return Ok(XmlListObject::new(activation, matched_children, Some(self.into())).into()); + return Ok(XmlListObject::new( + activation, + matched_children, + Some(self.into()), + Some(name.clone()), + ) + .into()); } fn call_property_local(