Skip to content

Commit

Permalink
avm2: Implement XML.setName (ruffle-rs#12979)
Browse files Browse the repository at this point in the history
* avm2/tests: Implement XML.setName; add a test

* avm2: Basic support for QNames in XML.setName (no namespace support yet)

* avm2: Reorder order of Attribute/Element/PI checks in XML.setName

* avm2: Throw error ruffle-rs#1117 when the name passed to XML.setName is not a valid XML name
  • Loading branch information
Lord-McSweeney authored Sep 7, 2023
1 parent 0e507e8 commit 20db9f8
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 2 deletions.
4 changes: 4 additions & 0 deletions core/src/avm2/e4x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,10 @@ impl<'gc> E4XNode<'gc> {
self.0.read().namespace
}

pub fn set_local_name(&self, name: AvmString<'gc>, mc: &Mutation<'gc>) {
self.0.write(mc).local_name = Some(name);
}

pub fn local_name(&self) -> Option<AvmString<'gc>> {
self.0.read().local_name
}
Expand Down
1 change: 1 addition & 0 deletions core/src/avm2/globals/XML.as
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ package {
AS3 native function hasComplexContent():Boolean;
AS3 native function hasSimpleContent():Boolean;
AS3 native function name():Object;
AS3 native function setName(name:*):void;
AS3 native function namespace(prefix:String = null):*;
AS3 native function localName():Object;
AS3 native function toXMLString():String;
Expand Down
47 changes: 47 additions & 0 deletions core/src/avm2/globals/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,53 @@ pub fn name<'gc>(
}
}

pub fn set_name<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let xml = this.as_xml_object().unwrap();
let node = xml.node();

let is_attribute_or_element = matches!(
&*node.kind(),
E4XNodeKind::Attribute(_)
| E4XNodeKind::ProcessingInstruction(_)
| E4XNodeKind::Element { .. }
);

if !is_attribute_or_element {
return Ok(Value::Undefined);
}

let new_name = args.get_value(0);

let new_name = if let Some(qname) = new_name.as_object().and_then(|q| q.as_qname_object()) {
let has_no_ns = qname.name().is_any_namespace()
|| (qname.name().namespace_set().len() == 1
&& qname.name().namespace_set()[0].is_public());
if !has_no_ns {
avm2_stub_method!(activation, "XML", "setName", "with QName namespaces");
}
qname.local_name()
} else {
new_name.coerce_to_string(activation)?
};

let is_name_valid = crate::avm2::e4x::is_xml_name(activation, new_name.into())?;
if !is_name_valid {
return Err(Error::AvmError(type_error(
activation,
&format!("Error #1117: Invalid XML name: {}.", new_name),
1117,
)?));
}

node.set_local_name(new_name, activation.context.gc_context);

Ok(Value::Undefined)
}

pub fn namespace<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Object<'gc>,
Expand Down
23 changes: 23 additions & 0 deletions tests/tests/swfs/avm2/xml_set_name/Test.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package {
import flash.display.MovieClip;

public class Test extends MovieClip {
public function Test() {
var a:XML = <outer attrib="value"><inner>innerText</inner></outer>;
var b:XML = new XML("justText");
trace(a.toXMLString());
a.setName("newOuterName");
trace(a.toXMLString());
a.setName(new QName(null,"someOuterName"));
trace(a.toXMLString());
a.setName(new QName("","otherOuterName"));
trace(a.toXMLString());
a.@attrib.setName("newattribname");
trace(a.toXMLString());
trace(b.toXMLString());
b.setName("noeffect");
trace(b.toXMLString());
}
}
}

17 changes: 17 additions & 0 deletions tests/tests/swfs/avm2/xml_set_name/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<outer attrib="value">
<inner>innerText</inner>
</outer>
<newOuterName attrib="value">
<inner>innerText</inner>
</newOuterName>
<someOuterName attrib="value">
<inner>innerText</inner>
</someOuterName>
<otherOuterName attrib="value">
<inner>innerText</inner>
</otherOuterName>
<otherOuterName newattribname="value">
<inner>innerText</inner>
</otherOuterName>
justText
justText
Binary file added tests/tests/swfs/avm2/xml_set_name/test.swf
Binary file not shown.
1 change: 1 addition & 0 deletions tests/tests/swfs/avm2/xml_set_name/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
num_frames = 1
1 change: 0 additions & 1 deletion tests/tests/swfs/from_avmplus/e4x/XML/e13_4_4_37/test.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
num_ticks = 1
known_failure = true
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
num_ticks = 1
known_failure = true

0 comments on commit 20db9f8

Please sign in to comment.