From fe8390760af39b12a4a3d1296516a7a557a15459 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Thu, 14 Sep 2023 00:18:22 +0200 Subject: [PATCH] avm2: Support node namespace in XML.namespace --- core/src/avm2/globals/XML.as | 11 ++++--- core/src/avm2/globals/xml.rs | 58 ++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/core/src/avm2/globals/XML.as b/core/src/avm2/globals/XML.as index d32b455bd..23e3cb043 100644 --- a/core/src/avm2/globals/XML.as +++ b/core/src/avm2/globals/XML.as @@ -8,7 +8,7 @@ package { stub_method("XML", "normalize"); return this; } - + AS3 static function setSettings(settings:Object = null): void { if (settings == null) { settings = XML.AS3::defaultSettings(); @@ -60,7 +60,10 @@ package { AS3 native function hasSimpleContent():Boolean; AS3 native function name():Object; AS3 native function setName(name:*):void; - AS3 native function namespace(prefix:String = null):*; + private native function namespace_internal_impl(hasPrefix:Boolean, prefix:String = null):*; + AS3 function namespace(prefix:String = null):* { + return namespace_internal_impl(arguments.length > 0, prefix); + } AS3 native function localName():Object; AS3 native function toXMLString():String; AS3 native function child(name:Object):XMLList; @@ -120,7 +123,7 @@ package { prototype.namespace = function(prefix:String = null):* { var self:XML = this; - return self.AS3::namespace(prefix); + return self.AS3::namespace.apply(self, arguments); } prototype.localName = function():Object { @@ -205,7 +208,7 @@ package { var self:XML = this; return self.AS3::text(); }; - + prototype.normalize = function():XML { var self:XML = this; return self.AS3::normalize(); diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index e834325f8..2a890a1c3 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -8,6 +8,7 @@ use crate::avm2::object::{ }; use crate::avm2::parameters::ParametersExt; use crate::avm2::string::AvmString; +use crate::avm2::Namespace; use crate::avm2::{Activation, Error, Multiname, Object, Value}; use crate::avm2_stub_method; @@ -128,15 +129,60 @@ pub fn set_name<'gc>( Ok(Value::Undefined) } -pub fn namespace<'gc>( +// namespace_internal_impl(hasPrefix:Boolean, prefix:String = null):* +pub fn namespace_internal_impl<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, - _args: &[Value<'gc>], + this: Object<'gc>, + args: &[Value<'gc>], ) -> Result, Error<'gc>> { - // FIXME: Implement namespace support (including prefix) avm2_stub_method!(activation, "XML", "namespace"); - let namespace = activation.avm2().public_namespace; - Ok(NamespaceObject::from_namespace(activation, namespace)?.into()) + + // FIXME: + // 1. Let y = x + // 2. Let inScopeNS = { } + // 3. While (y is not null) + // a. For each ns in y.[[InScopeNamespaces]] + // .... + + let xml = this.as_xml_object().unwrap(); + let node = xml.node(); + + // 4. If prefix was not specified + if args[0] == Value::Bool(false) { + // a. If x.[[Class]] ∈ {"text", "comment", "processing-instruction"}, return null + if matches!( + &*node.kind(), + E4XNodeKind::Text(_) + | E4XNodeKind::CData(_) + | E4XNodeKind::Comment(_) + | E4XNodeKind::ProcessingInstruction(_) + ) { + return Ok(Value::Null); + } + + // b. Return the result of calling the [[GetNamespace]] method of x.[[Name]] with argument inScopeNS + // FIXME: Use inScopeNS + let namespace = match node.namespace() { + Some(ns) => Namespace::package(ns, &mut activation.context.borrow_gc()), + None => activation.avm2().public_namespace, + }; + Ok(NamespaceObject::from_namespace(activation, namespace)?.into()) + } else { + // a. Let prefix = ToString(prefix) + let prefix = args.get_string(activation, 1)?; + + // b. Find a Namespace ns ∈ inScopeNS, such that ns.prefix = prefix. If no such ns exists, let ns = undefined. + // c. Return ns + + // FIXME: Nodes currently either have zero or one namespace, which has the prefix "" (empty string) + Ok(match node.namespace() { + Some(ns) if prefix.is_empty() => { + let namespace = Namespace::package(ns, &mut activation.context.borrow_gc()); + NamespaceObject::from_namespace(activation, namespace)?.into() + } + _ => Value::Undefined, + }) + } } pub fn local_name<'gc>(