avm2: Add target property to XMLListObject

This commit is contained in:
sleepycatcoding 2023-09-19 17:05:29 +03:00 committed by TÖRÖK Attila
parent a3b95d9534
commit 4285d998dc
6 changed files with 111 additions and 41 deletions

View File

@ -2140,7 +2140,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
) => { ) => {
let mut children = value1.children().clone(); let mut children = value1.children().clone();
children.push(E4XOrXml::Xml(value2)); children.push(E4XOrXml::Xml(value2));
XmlListObject::new(self, children, None).into() XmlListObject::new(self, children, None, None).into()
} }
( (
Value::Object(Object::XmlObject(value1)), Value::Object(Object::XmlObject(value1)),
@ -2148,14 +2148,14 @@ impl<'a, 'gc> Activation<'a, 'gc> {
) => { ) => {
let mut children = vec![E4XOrXml::Xml(value1)]; let mut children = vec![E4XOrXml::Xml(value1)];
children.extend(value2.children().clone()); 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(value1)),
Value::Object(Object::XmlObject(value2)), Value::Object(Object::XmlObject(value2)),
) => { ) => {
let children = vec![E4XOrXml::Xml(value1), E4XOrXml::Xml(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) => { (value1, value2) => {
let prim_value1 = value1.coerce_to_primitive(None, self)?; let prim_value1 = value1.coerce_to_primitive(None, self)?;

View File

@ -224,7 +224,7 @@ pub fn child<'gc>(
} else { } else {
Vec::new() 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() 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>( pub fn child_index<'gc>(
@ -281,7 +282,14 @@ pub fn children<'gc>(
Vec::new() 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>( pub fn copy<'gc>(
@ -329,7 +337,7 @@ pub fn elements<'gc>(
Vec::new() 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>( pub fn attributes<'gc>(
@ -344,7 +352,14 @@ pub fn attributes<'gc>(
Vec::new() 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>( pub fn attribute<'gc>(
@ -364,7 +379,8 @@ pub fn attribute<'gc>(
Vec::new() 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>( pub fn call_handler<'gc>(
@ -510,9 +526,10 @@ pub fn descendants<'gc>(
let multiname = name_to_multiname(activation, &args[0], false)?; let multiname = name_to_multiname(activation, &args[0], false)?;
let mut descendants = Vec::new(); let mut descendants = Vec::new();
xml.node().descendants(&multiname, &mut descendants); 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>( pub fn text<'gc>(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
this: Object<'gc>, this: Object<'gc>,
@ -528,7 +545,9 @@ pub fn text<'gc>(
} else { } else {
Vec::new() 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>( pub fn length<'gc>(
@ -559,6 +578,7 @@ pub fn has_simple_content<'gc>(
Ok(result.into()) Ok(result.into())
} }
// ECMA-357 13.4.4.9 XML.prototype.comments ( )
pub fn comments<'gc>( pub fn comments<'gc>(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
this: Object<'gc>, this: Object<'gc>,
@ -575,9 +595,12 @@ pub fn comments<'gc>(
Vec::new() 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>( pub fn processing_instructions<'gc>(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
this: Object<'gc>, this: Object<'gc>,
@ -598,7 +621,9 @@ pub fn processing_instructions<'gc>(
Vec::new() 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) // ECMA-357 13.4.4.18 XML.prototype.insertChildAfter (child1, child2)

View File

@ -6,6 +6,7 @@ pub use crate::avm2::object::xml_list_allocator;
use crate::avm2::{ use crate::avm2::{
e4x::{name_to_multiname, simple_content_to_string, E4XNode, E4XNodeKind}, e4x::{name_to_multiname, simple_content_to_string, E4XNode, E4XNodeKind},
error::type_error, error::type_error,
multiname::Multiname,
object::{E4XOrXml, XmlListObject}, object::{E4XOrXml, XmlListObject},
parameters::ParametersExt, parameters::ParametersExt,
string::AvmString, 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>( pub fn children<'gc>(
@ -192,7 +193,14 @@ pub fn children<'gc>(
sub_children.extend(children.iter().map(|node| E4XOrXml::E4X(*node))); 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>( 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>( 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>( 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>( 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>( 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())
} }

View File

@ -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<AvmString<'gc>>) -> Self { pub fn new(ns: Namespace<'gc>, name: impl Into<AvmString<'gc>>) -> Self {
Self { Self {
ns: NamespaceSet::single(ns), ns: NamespaceSet::single(ns),

View File

@ -26,7 +26,8 @@ pub fn xml_list_allocator<'gc>(
children: Vec::new(), children: Vec::new(),
// An XMLList created by 'new XMLList()' is not linked // An XMLList created by 'new XMLList()' is not linked
// to any object // to any object
target: None, target_object: None,
target_property: None,
}, },
)) ))
.into()) .into())
@ -52,7 +53,8 @@ impl<'gc> XmlListObject<'gc> {
pub fn new( pub fn new(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
children: Vec<E4XOrXml<'gc>>, children: Vec<E4XOrXml<'gc>>,
target: Option<Object<'gc>>, target_object: Option<Object<'gc>>,
target_property: Option<Multiname<'gc>>,
) -> Self { ) -> Self {
let base = ScriptObjectData::new(activation.context.avm2.classes().xml_list); let base = ScriptObjectData::new(activation.context.avm2.classes().xml_list);
XmlListObject(GcCell::new( XmlListObject(GcCell::new(
@ -60,7 +62,8 @@ impl<'gc> XmlListObject<'gc> {
XmlListObjectData { XmlListObjectData {
base, base,
children, children,
target, target_object,
target_property,
}, },
)) ))
} }
@ -94,8 +97,12 @@ impl<'gc> XmlListObject<'gc> {
self.0.write(mc).children = children; self.0.write(mc).children = children;
} }
pub fn target(&self) -> Option<Object<'gc>> { pub fn target_object(&self) -> Option<Object<'gc>> {
self.0.read().target self.0.read().target_object
}
pub fn target_property(&self) -> Option<Multiname<'gc>> {
self.0.read().target_property.clone()
} }
pub fn deep_copy(&self, activation: &mut Activation<'_, 'gc>) -> XmlListObject<'gc> { pub fn deep_copy(&self, activation: &mut Activation<'_, 'gc>) -> XmlListObject<'gc> {
@ -104,7 +111,12 @@ impl<'gc> XmlListObject<'gc> {
.iter() .iter()
.map(|child| E4XOrXml::E4X(child.node().deep_copy(activation.context.gc_context))) .map(|child| E4XOrXml::E4X(child.node().deep_copy(activation.context.gc_context)))
.collect(); .collect();
XmlListObject::new(activation, children, self.target()) XmlListObject::new(
activation,
children,
self.target_object(),
self.target_property(),
)
} }
pub fn equals( pub fn equals(
@ -160,7 +172,7 @@ impl<'gc> XmlListObject<'gc> {
let mut out = vec![]; let mut out = vec![];
out.extend(left.children().clone()); out.extend(left.children().clone());
out.extend(right.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. /// The XML or XMLList object that this list was created from.
/// If `Some`, then modifications to this list are reflected /// If `Some`, then modifications to this list are reflected
/// in the original object. /// in the original object.
target: Option<Object<'gc>>, target_object: Option<Object<'gc>>,
target_property: Option<Multiname<'gc>>,
} }
/// Holds either an `E4XNode` or an `XmlObject`. This can be converted /// 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() { for child in self.0.read().children.iter() {
child.node().descendants(multiname, &mut descendants); child.node().descendants(multiname, &mut descendants);
} }
Some(XmlListObject::new( Some(XmlListObject::new(activation, descendants, None, None))
activation,
descendants,
Some((*self).into()),
))
} }
fn get_property_local( fn get_property_local(
@ -309,7 +319,13 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> {
}) })
.collect(); .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( 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 Some(local_name) = name.local_name() {
if let Ok(index) = local_name.parse::<usize>() { if let Ok(index) = local_name.parse::<usize>() {
// 2.a. If x.[[TargetObject]] is not null // 2.a. If x.[[TargetObject]] is not null
if let Some(target) = write.target { if let Some(target) = write.target_object {
return Err(format!( return Err(format!(
"Modifying an XMLList object is not yet implemented: target {:?}", "Modifying an XMLList object is not yet implemented: target {:?}",
target target

View File

@ -183,11 +183,7 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
) -> Option<XmlListObject<'gc>> { ) -> Option<XmlListObject<'gc>> {
let mut descendants = Vec::new(); let mut descendants = Vec::new();
self.0.read().node.descendants(multiname, &mut descendants); self.0.read().node.descendants(multiname, &mut descendants);
Some(XmlListObject::new( Some(XmlListObject::new(activation, descendants, None, None))
activation,
descendants,
Some((*self).into()),
))
} }
fn get_property_local( fn get_property_local(
@ -236,7 +232,13 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
Vec::new() 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( fn call_property_local(