From cf5c02ca1b94c94b2492c82aafb0b5efdac49b82 Mon Sep 17 00:00:00 2001 From: Lord-McSweeney Date: Thu, 27 Jul 2023 03:03:35 -0700 Subject: [PATCH] avm2+tests: Fully implement XML.appendChild, add a test --- core/src/avm2/globals/xml.rs | 53 +++++++++++++++--- tests/tests/swfs/avm2/xml_appendchild/Test.as | 27 +++++++++ .../swfs/avm2/xml_appendchild/output.txt | 10 ++++ .../tests/swfs/avm2/xml_appendchild/test.swf | Bin 0 -> 688 bytes .../tests/swfs/avm2/xml_appendchild/test.toml | 1 + 5 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 tests/tests/swfs/avm2/xml_appendchild/Test.as create mode 100644 tests/tests/swfs/avm2/xml_appendchild/output.txt create mode 100644 tests/tests/swfs/avm2/xml_appendchild/test.swf create mode 100644 tests/tests/swfs/avm2/xml_appendchild/test.toml diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index f3f2f16ef..015a8a651 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -314,22 +314,59 @@ pub fn append_child<'gc>( ) -> Result, Error<'gc>> { let xml = this.as_xml_object().unwrap(); - let child = args.get_object(activation, 0, "child")?; - if let Some(child) = child.as_xml_object() { + let child = args.get_value(0); + if let Some(child) = child.as_object().and_then(|o| o.as_xml_object()) { xml.node() .append_child(activation.context.gc_context, *child.node())?; - } else if let Some(list) = child.as_xml_list_object() { - if list.target().is_some() { - return Err("Cannot append XMLList with target".into()); - } + } else if let Some(list) = child.as_object().and_then(|o| o.as_xml_list_object()) { for child in &*list.children() { xml.node() .append_child(activation.context.gc_context, *child.node())?; } } else { - return Err(format!("Cannot append non-XML value {child:?}").into()); + // Appending a non-XML/XMLList object + let last_child_name = if let E4XNodeKind::Element { children, .. } = &*xml.node().kind() { + let num_children = children.len(); + + match num_children { + 0 => None, + _ => children[num_children - 1].local_name(), + } + } else { + // FIXME - figure out exactly when appending is allowed in FP, + // and throw the proper AVM error. + return Err(Error::RustError( + format!( + "Cannot append child {child:?} to node {:?}", + xml.node().kind() + ) + .into(), + )); + }; + + let text = child.coerce_to_string(activation)?; + if let Some(last_child_name) = last_child_name { + let element_node = + E4XNode::element(activation.context.gc_context, last_child_name, *xml.node()); // Creating an element requires passing a parent node, unlike creating a text node + + let text_node = E4XNode::text(activation.context.gc_context, text, None); + + element_node + .append_child(activation.context.gc_context, text_node) + .expect("Appending to an element node should succeed"); + + xml.node() + .append_child(activation.context.gc_context, element_node)?; + } else { + let node = E4XNode::text(activation.context.gc_context, text, None); + // The text node will be parented in the append_child operation + + xml.node() + .append_child(activation.context.gc_context, node)?; + } }; - Ok(Value::Undefined) + + Ok(this.into()) } pub fn descendants<'gc>( diff --git a/tests/tests/swfs/avm2/xml_appendchild/Test.as b/tests/tests/swfs/avm2/xml_appendchild/Test.as new file mode 100644 index 000000000..09eddd803 --- /dev/null +++ b/tests/tests/swfs/avm2/xml_appendchild/Test.as @@ -0,0 +1,27 @@ +package { + import flash.display.MovieClip; + + public class Test extends MovieClip { + + public function Test() { + XML.prettyPrinting = false; + var xml:XML = ; + trace(xml); + var xmls:XMLList = ().children(); + var appended:XML = xml.appendChild(xmls); + trace(appended); + trace(xml); + trace(xml == appended); + xml.child3 = "4"; + trace(xmls); + xml.appendChild("qwerty"); + trace(xml); + trace(xml.appendChild({"key":"value"})); + var xml2:XML = abcd; + trace(xml2.appendChild("text1").toXMLString()); + xml2 = ; + trace(xml2.appendChild("text2").toXMLString()); + } + } +} + diff --git a/tests/tests/swfs/avm2/xml_appendchild/output.txt b/tests/tests/swfs/avm2/xml_appendchild/output.txt new file mode 100644 index 000000000..e9eb1ebe2 --- /dev/null +++ b/tests/tests/swfs/avm2/xml_appendchild/output.txt @@ -0,0 +1,10 @@ + + + +true +4 + +4qwerty +4qwerty[object Object] +abcdtext1 +text2 diff --git a/tests/tests/swfs/avm2/xml_appendchild/test.swf b/tests/tests/swfs/avm2/xml_appendchild/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..e82a23fd3c5ad725d505571d16f2b5f2381cbf30 GIT binary patch literal 688 zcmV;h0#E%zS5pxZ1ONbdoPAQ=Qqw>f-JfhWY3MIlFo1xf_!FB@7%!MkM=0Vj1L6!i z!%fGe?MkB|sp(SSjz{Ue58<8H1xCH{8TtsgX%wkCW|G~LbIyL>*_}NG^Z7(+Fy;P!A5w)!iktXjxCp z+M(-l*9X!o*5>j~?H#Lgbvx*|tm3(?$r|)?q%6D2LaZEF6hzvxsf0QF}8Q#)n$2Ttyih=Hn>y!{on% z%?z9ViaGh8B2(8xuKclsLFj_hp0`r1ka2$UGIV`$nEQBddkd8urCh2vU9YjInm1xq(gv>}QYfh`h{6;0B<=6(7~Zf0v7B`-HP&zDUXuKfpzNeBepqYez$oaB(n9iJP!S zMuB-m@C44w`H^v?r}VU*(X)C^AJs7#!w@AAq>7r*Mv_=crAH~k6iF(Eln_cNB?=`f zB?&5P6y2aGuTCNgrzo1H@V0sfsSlC5h{Ux;;+7`CV1`gqB>)A45rzN*1fjanv#Que zmaSU0V%gNPWy>a(Es1vzOvg_XJ{JWflF&ZGp4Ep1km^GdX8N#*vVCY_y|)Q$ZNW*{ znlWxnbd8%`L+`G^Q|(JNceay*g1=?VbdA}rF(>$qBsfidJv-k>3(L1^?m}2%qZltf ziuuf#cQV!7`2gPCN&l9Od&a_RC|1U0?;8&Wjp|Z0SCfoKLfFWHUz%}Udwivd?L?bT W;GQL*Its-ZMVAgd72pRQuoH