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();
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)?;

View File

@ -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)

View File

@ -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())
}

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 {
Self {
ns: NamespaceSet::single(ns),

View File

@ -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<E4XOrXml<'gc>>,
target: Option<Object<'gc>>,
target_object: Option<Object<'gc>>,
target_property: Option<Multiname<'gc>>,
) -> 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<Object<'gc>> {
self.0.read().target
pub fn target_object(&self) -> Option<Object<'gc>> {
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> {
@ -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<Object<'gc>>,
target_object: Option<Object<'gc>>,
target_property: Option<Multiname<'gc>>,
}
/// 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::<usize>() {
// 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

View File

@ -183,11 +183,7 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
) -> Option<XmlListObject<'gc>> {
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(