avm2: Alternative implementation of XML hasOwnProperty @attribute

This commit is contained in:
Tom Schuster 2023-04-28 12:19:16 +02:00 committed by Aaron Hill
parent 24079518d9
commit 791081051f
7 changed files with 59 additions and 25 deletions

View File

@ -715,3 +715,30 @@ pub fn to_xml_string<'gc>(
to_xml_string_inner(xml, &mut buf)?; to_xml_string_inner(xml, &mut buf)?;
Ok(AvmString::new(activation.context.gc_context, buf)) Ok(AvmString::new(activation.context.gc_context, buf))
} }
pub fn name_to_multiname<'gc>(
activation: &mut Activation<'_, 'gc>,
name: &Value<'gc>,
) -> Result<Multiname<'gc>, Error<'gc>> {
if let Value::Object(o) = name {
if let Some(qname) = o.as_qname_object() {
return Ok(qname.name().clone());
}
}
let name = name.coerce_to_string(activation)?;
if let Some(name) = name.strip_prefix(b'@') {
let name = AvmString::new(activation.context.gc_context, name);
return Ok(Multiname::attribute(
activation.avm2().public_namespace,
name,
));
}
Ok(if &*name == b"*" {
Multiname::any(activation.context.gc_context)
} else {
Multiname::new(activation.avm2().public_namespace, name)
})
}

View File

@ -210,8 +210,7 @@ pub fn has_own_property<'gc>(
args.get(0).ok_or_else(|| "No name specified".into()); args.get(0).ok_or_else(|| "No name specified".into());
let name = name?.coerce_to_string(activation)?; let name = name?.coerce_to_string(activation)?;
let multiname = Multiname::new(activation.avm2().public_namespace, name); Ok(this.has_own_property_string(name, activation)?.into())
Ok(this.has_own_property(&multiname).into())
} }
/// `Object.prototype.isPrototypeOf` /// `Object.prototype.isPrototypeOf`

View File

@ -1,6 +1,6 @@
//! XML builtin and prototype //! XML builtin and prototype
use crate::avm2::e4x::{E4XNode, E4XNodeKind}; use crate::avm2::e4x::{name_to_multiname, E4XNode, E4XNodeKind};
pub use crate::avm2::object::xml_allocator; pub use crate::avm2::object::xml_allocator;
use crate::avm2::object::{ use crate::avm2::object::{
E4XOrXml, NamespaceObject, QNameObject, TObject, XmlListObject, XmlObject, E4XOrXml, NamespaceObject, QNameObject, TObject, XmlListObject, XmlObject,
@ -95,24 +95,6 @@ pub fn to_xml_string<'gc>(
Ok(Value::String(node.xml_to_xml_string(activation)?)) Ok(Value::String(node.xml_to_xml_string(activation)?))
} }
pub fn name_to_multiname<'gc>(
activation: &mut Activation<'_, 'gc>,
name: &Value<'gc>,
) -> Result<Multiname<'gc>, Error<'gc>> {
if let Value::Object(o) = name {
if let Some(qname) = o.as_qname_object() {
return Ok(qname.name().clone());
}
}
let name = name.coerce_to_string(activation)?;
Ok(if &*name == b"*" {
Multiname::any(activation.context.gc_context)
} else {
Multiname::new(activation.avm2().public_namespace, name)
})
}
pub fn child<'gc>( pub fn child<'gc>(
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc>,
this: Option<Object<'gc>>, this: Option<Object<'gc>>,

View File

@ -4,15 +4,13 @@ use ruffle_wstr::WString;
pub use crate::avm2::object::xml_list_allocator; pub use crate::avm2::object::xml_list_allocator;
use crate::avm2::{ use crate::avm2::{
e4x::{simple_content_to_string, E4XNode, E4XNodeKind}, e4x::{name_to_multiname, simple_content_to_string, E4XNode, E4XNodeKind},
error::type_error, error::type_error,
object::{E4XOrXml, XmlListObject}, object::{E4XOrXml, XmlListObject},
string::AvmString, string::AvmString,
Activation, Error, Multiname, Object, TObject, Value, Activation, Error, Multiname, Object, TObject, Value,
}; };
use super::xml::name_to_multiname;
fn has_simple_content_inner(children: &[E4XOrXml<'_>]) -> bool { fn has_simple_content_inner(children: &[E4XOrXml<'_>]) -> bool {
match children { match children {
[] => true, [] => true,

View File

@ -314,6 +314,16 @@ impl<'gc> Multiname<'gc> {
} }
} }
/// Creates a new Multiname with the `MultinameFlags::ATTRIBUTE` flag.
pub fn attribute(ns: Namespace<'gc>, name: impl Into<AvmString<'gc>>) -> Self {
Self {
ns: NamespaceSet::single(ns),
name: Some(name.into()),
params: Vec::new(),
flags: MultinameFlags::ATTRIBUTE,
}
}
pub fn namespace_set(&self) -> &[Namespace<'gc>] { pub fn namespace_set(&self) -> &[Namespace<'gc>] {
match &self.ns { match &self.ns {
NamespaceSet::Single(ns) => std::slice::from_ref(ns), NamespaceSet::Single(ns) => std::slice::from_ref(ns),

View File

@ -586,6 +586,15 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
self.base().has_own_property(name) self.base().has_own_property(name)
} }
/// Same as has_own_property, but constructs a public Multiname for you.
fn has_own_property_string(
self,
name: impl Into<AvmString<'gc>>,
activation: &mut Activation<'_, 'gc>,
) -> Result<bool, Error<'gc>> {
Ok(self.has_own_property(&Multiname::new(activation.avm2().public_namespace, name)))
}
/// Returns true if an object has one or more traits of a given name. /// Returns true if an object has one or more traits of a given name.
fn has_trait(self, name: &Multiname<'gc>) -> bool { fn has_trait(self, name: &Multiname<'gc>) -> bool {
let base = self.base(); let base = self.base();

View File

@ -1,7 +1,7 @@
//! Object representation for XML objects //! Object representation for XML objects
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::e4x::{E4XNode, E4XNodeKind}; use crate::avm2::e4x::{name_to_multiname, E4XNode, E4XNodeKind};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject, XmlListObject}; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject, XmlListObject};
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
@ -279,6 +279,15 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
read.base.has_own_dynamic_property(name) read.base.has_own_dynamic_property(name)
} }
fn has_own_property_string(
self,
name: impl Into<AvmString<'gc>>,
activation: &mut Activation<'_, 'gc>,
) -> Result<bool, Error<'gc>> {
let name = name_to_multiname(activation, &Value::String(name.into()))?;
Ok(self.has_own_property(&name))
}
fn set_property_local( fn set_property_local(
self, self,
name: &Multiname<'gc>, name: &Multiname<'gc>,