avm2: Add IS_QNAME flag to Multiname, improve XML name matching

This commit is contained in:
Adrian Wielgosik 2024-04-03 00:31:48 +02:00 committed by Adrian Wielgosik
parent d7b3a500d7
commit fd281cc715
6 changed files with 83 additions and 8 deletions

View File

@ -1055,14 +1055,18 @@ impl<'gc> E4XNode<'gc> {
return false; return false;
} }
// The Multiname is not a QName, so an any name matches everything.
// See https://github.com/adobe/avmplus/blob/858d034a3bd3a54d9b70909386435cf4aec81d21/core/Multiname.cpp#L59
if name.is_any_name() && !name.is_qname() {
return true;
}
if !name.is_any_name() && self.local_name() != name.local_name() { if !name.is_any_name() && self.local_name() != name.local_name() {
return false; return false;
} }
// The Multiname is not a QName, so an any name matches everything. if self.local_name().is_none() {
// See https://github.com/adobe/avmplus/blob/858d034a3bd3a54d9b70909386435cf4aec81d21/core/Multiname.cpp#L59 return false;
if name.is_any_name() && name.namespace_set().len() > 1 {
return true;
} }
if name.is_any_namespace() { if name.is_any_namespace() {

View File

@ -68,6 +68,12 @@ bitflags! {
const HAS_LAZY_NAME = 1 << 1; const HAS_LAZY_NAME = 1 << 1;
/// Whether this was a 'MultinameA' - used for XML attribute lookups /// Whether this was a 'MultinameA' - used for XML attribute lookups
const ATTRIBUTE = 1 << 2; const ATTRIBUTE = 1 << 2;
/// Represents the XML concept of "qualified name".
/// This also distinguishes a QName(x, y) from Multiname(x, [y])
/// Basically, marks multinames that come from multinames of kind `(RT)QName(L)(A)`
/// (and dynamically-generated multinames that are supposed to be equivalent to one).
const IS_QNAME = 1 << 3;
} }
} }
@ -121,6 +127,15 @@ impl<'gc> Multiname<'gc> {
self.flags.set(MultinameFlags::ATTRIBUTE, is_attribute); self.flags.set(MultinameFlags::ATTRIBUTE, is_attribute);
} }
#[inline(always)]
pub fn is_qname(&self) -> bool {
self.flags.contains(MultinameFlags::IS_QNAME)
}
pub fn set_is_qname(&mut self, is_qname: bool) {
self.flags.set(MultinameFlags::IS_QNAME, is_qname);
}
/// Read a namespace set from the ABC constant pool, and return a list of /// Read a namespace set from the ABC constant pool, and return a list of
/// copied namespaces. /// copied namespaces.
pub fn abc_namespace_set( pub fn abc_namespace_set(
@ -175,7 +190,7 @@ impl<'gc> Multiname<'gc> {
.pool_string_option(name.0, &mut context.borrow_gc())? .pool_string_option(name.0, &mut context.borrow_gc())?
.map(|v| v.into()), .map(|v| v.into()),
param: None, param: None,
flags: Default::default(), flags: MultinameFlags::IS_QNAME,
} }
} }
AbcMultiname::RTQName { name } | AbcMultiname::RTQNameA { name } => Self { AbcMultiname::RTQName { name } | AbcMultiname::RTQNameA { name } => Self {
@ -184,13 +199,15 @@ impl<'gc> Multiname<'gc> {
.pool_string_option(name.0, &mut context.borrow_gc())? .pool_string_option(name.0, &mut context.borrow_gc())?
.map(|v| v.into()), .map(|v| v.into()),
param: None, param: None,
flags: MultinameFlags::HAS_LAZY_NS, flags: MultinameFlags::HAS_LAZY_NS | MultinameFlags::IS_QNAME,
}, },
AbcMultiname::RTQNameL | AbcMultiname::RTQNameLA => Self { AbcMultiname::RTQNameL | AbcMultiname::RTQNameLA => Self {
ns: NamespaceSet::multiple(vec![], mc), ns: NamespaceSet::multiple(vec![], mc),
name: None, name: None,
param: None, param: None,
flags: MultinameFlags::HAS_LAZY_NS | MultinameFlags::HAS_LAZY_NAME, flags: MultinameFlags::HAS_LAZY_NS
| MultinameFlags::HAS_LAZY_NAME
| MultinameFlags::IS_QNAME,
}, },
AbcMultiname::Multiname { AbcMultiname::Multiname {
namespace_set, namespace_set,
@ -287,7 +304,7 @@ impl<'gc> Multiname<'gc> {
ns, ns,
name, name,
param: self.param, param: self.param,
flags: self.flags & MultinameFlags::ATTRIBUTE, flags: self.flags & (MultinameFlags::ATTRIBUTE | MultinameFlags::IS_QNAME),
}) })
} }

View File

@ -0,0 +1,21 @@
getdescendants QName(null, null)
element
element
getdescendants Multiname(null, [Namespace("")])
text
element
text
element
text
text
text
getdescendants Multiname(null, [Namespace(""), Namespace("x")])
text
element
text
element
text
text
text

View File

@ -0,0 +1,32 @@
// compiled with mxmlc, with bytecode modifications in FFDEC
import flash.utils.getQualifiedClassName;
import flash.utils.getTimer;
class C{
public function test(x){
trace('getdescendants QName(null, null)')
var a = x; // note: put `getdescendants QName(null, null)` here
for each(var i in a) { trace(i.nodeKind()); }
trace();
trace('getdescendants Multiname(null, [Namespace("")])')
var b = x; // note: put `getdescendants Multiname(null, [Namespace("")])` here
for each(var i in b) { trace(i.nodeKind()); }
trace();
trace('getdescendants Multiname(null, [Namespace(""), Namespace("x")])')
var c = x; // note: put `getdescendants Multiname(null, [Namespace(""), Namespace("x")])` here
for each(var i in c) { trace(i.nodeKind()); }
}
}
XML.ignoreWhitespace = false;
var s = "<a> <b> x <c> y </c> </b> </a>";
var x = new XML(s);
new C().test(x);
package {
import flash.display.MovieClip;
public class Test extends MovieClip {
public function Test(){
}
}
}

Binary file not shown.

View File

@ -0,0 +1 @@
num_frames = 1