From f334963b47bd89f29aedd19f832a61b3e1341132 Mon Sep 17 00:00:00 2001 From: sleepycatcoding <131554884+sleepycatcoding@users.noreply.github.com> Date: Fri, 13 Oct 2023 00:24:20 +0300 Subject: [PATCH] avm2: Handle single element XMLLists in XML.insertChildBefore/After --- core/src/avm2/globals/xml.rs | 42 +++++++++++++------ .../from_avmplus/e4x/XML/bug157597/test.toml | 1 - .../e4x/XML/bug157597_2/test.toml | 1 - 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index 9a714ff07f2a..ab7c77df3d72 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -589,7 +589,7 @@ pub fn insert_child_after<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { let xml = this.as_xml_object().unwrap(); - let child1 = args.try_get_object(activation, 0); + let child1 = args.get_value(0); let child2 = args.get_value(1); let child2 = crate::avm2::e4x::maybe_escape_child(activation, child2)?; @@ -599,14 +599,23 @@ pub fn insert_child_after<'gc>( } // 3. Else if Type(child1) is XML - if let Some(child1) = child1.and_then(|x| x.as_xml_object()) { + if let Some(child1) = child1.as_object().and_then(|x| { + if let Some(xml) = x.as_xml_object() { + return Some(*xml.node()); + // NOTE: Non-standard avmplus behavior, single element XMLLists are treated as XML objects. + } else if let Some(list) = x.as_xml_list_object() { + if list.length() == 1 { + return Some(*list.children()[0].node()); + } + } + + None + }) { // NOTE: We fetch the index separately to avoid borrowing errors. let index = if let E4XNodeKind::Element { children, .. } = &*xml.node().kind() { // 3.a. For i = 0 to x.[[Length]]-1 // 3.a.i. If x[i] is the same object as child1 - children - .iter() - .position(|x| E4XNode::ptr_eq(*x, *child1.node())) + children.iter().position(|x| E4XNode::ptr_eq(*x, child1)) } else { None }; @@ -618,7 +627,7 @@ pub fn insert_child_after<'gc>( return Ok(xml.into()); } // 2. If (child1 == null) - } else { + } else if matches!(child1, Value::Null) { // 2.a. Call the [[Insert]] method of x with arguments "0" and child2 xml.node().insert(0, child2, activation)?; // 2.b. Return x @@ -636,7 +645,7 @@ pub fn insert_child_before<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { let xml = this.as_xml_object().unwrap(); - let child1 = args.try_get_object(activation, 0); + let child1 = args.get_value(0); let child2 = args.get_value(1); let child2 = crate::avm2::e4x::maybe_escape_child(activation, child2)?; @@ -646,14 +655,23 @@ pub fn insert_child_before<'gc>( } // 3. Else if Type(child1) is XML - if let Some(child1) = child1.and_then(|x| x.as_xml_object()) { + if let Some(child1) = child1.as_object().and_then(|x| { + if let Some(xml) = x.as_xml_object() { + return Some(*xml.node()); + // NOTE: Non-standard avmplus behavior, single element XMLLists are treated as XML objects. + } else if let Some(list) = x.as_xml_list_object() { + if list.length() == 1 { + return Some(*list.children()[0].node()); + } + } + + None + }) { // NOTE: We fetch the index separately to avoid borrowing errors. let index = if let E4XNodeKind::Element { children, .. } = &*xml.node().kind() { // 3.a. For i = 0 to x.[[Length]]-1 // 3.a.i. If x[i] is the same object as child1 - children - .iter() - .position(|x| E4XNode::ptr_eq(*x, *child1.node())) + children.iter().position(|x| E4XNode::ptr_eq(*x, child1)) } else { None }; @@ -665,7 +683,7 @@ pub fn insert_child_before<'gc>( return Ok(xml.into()); } // 2. If (child1 == null) - } else { + } else if matches!(child1, Value::Null) { let length = if let E4XNodeKind::Element { children, .. } = &*xml.node().kind() { children.len() } else { diff --git a/tests/tests/swfs/from_avmplus/e4x/XML/bug157597/test.toml b/tests/tests/swfs/from_avmplus/e4x/XML/bug157597/test.toml index 29f3cef79022..cf6123969a1d 100644 --- a/tests/tests/swfs/from_avmplus/e4x/XML/bug157597/test.toml +++ b/tests/tests/swfs/from_avmplus/e4x/XML/bug157597/test.toml @@ -1,2 +1 @@ num_ticks = 1 -known_failure = true diff --git a/tests/tests/swfs/from_avmplus/e4x/XML/bug157597_2/test.toml b/tests/tests/swfs/from_avmplus/e4x/XML/bug157597_2/test.toml index 29f3cef79022..cf6123969a1d 100644 --- a/tests/tests/swfs/from_avmplus/e4x/XML/bug157597_2/test.toml +++ b/tests/tests/swfs/from_avmplus/e4x/XML/bug157597_2/test.toml @@ -1,2 +1 @@ num_ticks = 1 -known_failure = true