diff --git a/core/src/avm2/globals/XMLList.as b/core/src/avm2/globals/XMLList.as index 624937705800..d639605c5d6e 100644 --- a/core/src/avm2/globals/XMLList.as +++ b/core/src/avm2/globals/XMLList.as @@ -14,6 +14,7 @@ package { AS3 native function length():int; AS3 native function child(name:Object):XMLList; AS3 native function children():XMLList; + AS3 native function contains(value:*):Boolean; AS3 native function copy():XMLList; AS3 native function attribute(name:*):XMLList; AS3 native function attributes():XMLList; @@ -87,6 +88,11 @@ package { return self.AS3::children(); } + prototype.contains = function(value:*):Boolean { + var self:XMLList = this; + return self.AS3::contains(value); + } + prototype.copy = function():XMLList { var self:XMLList = this; return self.AS3::copy(); diff --git a/core/src/avm2/globals/xml_list.rs b/core/src/avm2/globals/xml_list.rs index 2a9e2daf7b49..09979d44e7be 100644 --- a/core/src/avm2/globals/xml_list.rs +++ b/core/src/avm2/globals/xml_list.rs @@ -230,6 +230,33 @@ pub fn children<'gc>( .into()) } +/// 13.5.4.8 XMLList.prototype.contains (value) +pub fn contains<'gc>( + activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let list = this.as_xml_list_object().unwrap(); + let value = args.get_value(0); + let length = list.length(); + + // 1. For i = 0 to list.[[Length]]-1 + // NOTE: cannot use children_mut here since the value can be this same list, which causes a panic. + for index in 0..length { + let child = list + .xml_object_child(index, activation) + .expect("index should be in between 0 and length"); + + // 2.a. If the result of the comparison list[i] == value is true, return true + if child.abstract_eq(&value, activation)? { + return Ok(true.into()); + } + } + + // 2. Return false + Ok(false.into()) +} + pub fn copy<'gc>( activation: &mut Activation<'_, 'gc>, this: Object<'gc>, diff --git a/tests/tests/swfs/avm2/xml_contains/Test.as b/tests/tests/swfs/avm2/xml_contains/Test.as new file mode 100644 index 000000000000..27c6ff175495 --- /dev/null +++ b/tests/tests/swfs/avm2/xml_contains/Test.as @@ -0,0 +1,85 @@ +package { + import flash.display.Sprite; + public class Test extends Sprite {} +} + +var list1 = new XMLList("AB"); +var list2 = new XMLList("A"); +var list3 = new XMLList("B"); + +var x = new XML("A"); +var x1 = A; +var x2 = new XML("B"); + +var values = [null, undefined, "A", "B", "C", list1, list2, list3, x, x1, x2]; + +for (var i = 0; i < values.length; i++) { + for (var j = 0; j < values.length; j++) { + test(values[i], values[j]); + } +} + +function test(self, a) { + if (!(self is XMLList) && !(self is XML)) { + return; + } + + trace(repr(self) + ".contains(" + repr(a) + ")"); + try { + trace(self.contains(a)); + } catch (ex) { + trace("! " + ex); + } + trace(); +} + +function repr(value: *) { + if (value === undefined) { + return "undefined"; + } else if (value === null) { + return "null"; + } else if (value === list1) { + return "list1"; + } else if (value === list2) { + return "list2"; + } else if (value === list3) { + return "list3"; + } else if (value === x) { + return "x"; + } else if (value === x1) { + return "x1"; + } else if (value === x2) { + return "x2"; + } else if (value is String) { + return escapeString(value); + } else { + return typeof(value) + " " + value; + } +} + +function escapeString(input: String): String { + var output:String = "\""; + for (var i:int = 0; i < input.length; i++) { + var char:String = input.charAt(i); + switch (char) { + case "\\": + output += "\\\\"; + break; + case "\"": + output += "\\\""; + break; + case "\n": + output += "\\n"; + break; + case "\r": + output += "\\r"; + break; + case "\t": + output += "\\t"; + break; + default: + output += char; + } + } + return output + "\""; +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/xml_contains/output.txt b/tests/tests/swfs/avm2/xml_contains/output.txt new file mode 100644 index 000000000000..cf724c1629ff --- /dev/null +++ b/tests/tests/swfs/avm2/xml_contains/output.txt @@ -0,0 +1,198 @@ +list1.contains(null) +false + +list1.contains(undefined) +false + +list1.contains("A") +true + +list1.contains("B") +true + +list1.contains("C") +false + +list1.contains(list1) +false + +list1.contains(list2) +true + +list1.contains(list3) +true + +list1.contains(x) +true + +list1.contains(x1) +true + +list1.contains(x2) +true + +list2.contains(null) +false + +list2.contains(undefined) +false + +list2.contains("A") +true + +list2.contains("B") +false + +list2.contains("C") +false + +list2.contains(list1) +false + +list2.contains(list2) +true + +list2.contains(list3) +false + +list2.contains(x) +true + +list2.contains(x1) +true + +list2.contains(x2) +false + +list3.contains(null) +false + +list3.contains(undefined) +false + +list3.contains("A") +false + +list3.contains("B") +true + +list3.contains("C") +false + +list3.contains(list1) +false + +list3.contains(list2) +false + +list3.contains(list3) +true + +list3.contains(x) +false + +list3.contains(x1) +false + +list3.contains(x2) +true + +x.contains(null) +false + +x.contains(undefined) +false + +x.contains("A") +false + +x.contains("B") +false + +x.contains("C") +false + +x.contains(list1) +false + +x.contains(list2) +false + +x.contains(list3) +false + +x.contains(x) +true + +x.contains(x1) +true + +x.contains(x2) +false + +x1.contains(null) +false + +x1.contains(undefined) +false + +x1.contains("A") +false + +x1.contains("B") +false + +x1.contains("C") +false + +x1.contains(list1) +false + +x1.contains(list2) +false + +x1.contains(list3) +false + +x1.contains(x) +true + +x1.contains(x1) +true + +x1.contains(x2) +false + +x2.contains(null) +false + +x2.contains(undefined) +false + +x2.contains("A") +false + +x2.contains("B") +false + +x2.contains("C") +false + +x2.contains(list1) +false + +x2.contains(list2) +false + +x2.contains(list3) +false + +x2.contains(x) +false + +x2.contains(x1) +false + +x2.contains(x2) +true + diff --git a/tests/tests/swfs/avm2/xml_contains/test.swf b/tests/tests/swfs/avm2/xml_contains/test.swf new file mode 100644 index 000000000000..5ea496f4599f Binary files /dev/null and b/tests/tests/swfs/avm2/xml_contains/test.swf differ diff --git a/tests/tests/swfs/avm2/xml_contains/test.toml b/tests/tests/swfs/avm2/xml_contains/test.toml new file mode 100644 index 000000000000..cf6123969a1d --- /dev/null +++ b/tests/tests/swfs/avm2/xml_contains/test.toml @@ -0,0 +1 @@ +num_ticks = 1 diff --git a/tests/tests/swfs/from_avmplus/e4x/XML/e13_4_4_10/test.toml b/tests/tests/swfs/from_avmplus/e4x/XML/e13_4_4_10/test.toml index 29f3cef79022..cf6123969a1d 100644 --- a/tests/tests/swfs/from_avmplus/e4x/XML/e13_4_4_10/test.toml +++ b/tests/tests/swfs/from_avmplus/e4x/XML/e13_4_4_10/test.toml @@ -1,2 +1 @@ num_ticks = 1 -known_failure = true diff --git a/tests/tests/swfs/from_avmplus/e4x/XMLList/e13_5_4_7/test.toml b/tests/tests/swfs/from_avmplus/e4x/XMLList/e13_5_4_7/test.toml index 29f3cef79022..cf6123969a1d 100644 --- a/tests/tests/swfs/from_avmplus/e4x/XMLList/e13_5_4_7/test.toml +++ b/tests/tests/swfs/from_avmplus/e4x/XMLList/e13_5_4_7/test.toml @@ -1,2 +1 @@ num_ticks = 1 -known_failure = true