diff --git a/core/src/avm2/e4x.rs b/core/src/avm2/e4x.rs index 2ccaab3fb..5a7dc6aaf 100644 --- a/core/src/avm2/e4x.rs +++ b/core/src/avm2/e4x.rs @@ -108,6 +108,54 @@ impl<'gc> E4XNode<'gc> { )) } + pub fn deep_copy(&self, mc: MutationContext<'gc, '_>) -> Self { + let this = self.0.read(); + + let kind = match &this.kind { + E4XNodeKind::Text(string) => E4XNodeKind::Text(*string), + E4XNodeKind::CData(string) => E4XNodeKind::CData(*string), + E4XNodeKind::Comment(string) => E4XNodeKind::Comment(*string), + E4XNodeKind::ProcessingInstruction(string) => { + E4XNodeKind::ProcessingInstruction(*string) + } + E4XNodeKind::Attribute(string) => E4XNodeKind::Attribute(*string), + E4XNodeKind::Element { + attributes, + children, + } => E4XNodeKind::Element { + attributes: attributes.iter().map(|attr| attr.deep_copy(mc)).collect(), + children: children.iter().map(|child| child.deep_copy(mc)).collect(), + }, + }; + + let node = E4XNode(GcCell::allocate( + mc, + E4XNodeData { + parent: None, + local_name: this.local_name, + kind, + }, + )); + + if let E4XNodeKind::Element { + attributes, + children, + } = &mut node.0.write(mc).kind + { + for attr in attributes.iter_mut() { + let mut data = attr.0.write(mc); + data.parent = Some(node); + } + + for child in children.iter_mut() { + let mut data = child.0.write(mc); + data.parent = Some(node); + } + } + + node + } + pub fn remove_all_children(&self, gc_context: MutationContext<'gc, '_>) { let mut this = self.0.write(gc_context); if let E4XNodeKind::Element { children, .. } = &mut this.kind { diff --git a/core/src/avm2/globals/XML.as b/core/src/avm2/globals/XML.as index f0e871a49..4f2f099e0 100644 --- a/core/src/avm2/globals/XML.as +++ b/core/src/avm2/globals/XML.as @@ -31,8 +31,9 @@ package { AS3 native function localName():Object; AS3 native function toXMLString():String; AS3 native function child(name:Object):XMLList; - AS3 native function parent():*; AS3 native function children():XMLList; + AS3 native function copy():XML; + AS3 native function parent():*; AS3 native function elements(name:*):XMLList; AS3 native function attributes():XMLList; AS3 native function attribute(name:*):XMLList; @@ -75,7 +76,12 @@ package { var self:XML = this; return self.AS3::children(); }; - + + prototype.copy = function():XML { + var self:XML = this; + return self.AS3::copy(); + } + prototype.parent = function():* { var self:XML = this; return self.AS3::parent(); diff --git a/core/src/avm2/globals/xml.rs b/core/src/avm2/globals/xml.rs index 41addb90b..39a7b6424 100644 --- a/core/src/avm2/globals/xml.rs +++ b/core/src/avm2/globals/xml.rs @@ -149,6 +149,16 @@ pub fn children<'gc>( Ok(XmlListObject::new(activation, children, Some(xml.into())).into()) } +pub fn copy<'gc>( + activation: &mut Activation<'_, 'gc>, + this: Option>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let xml = this.unwrap().as_xml_object().unwrap(); + let node = xml.node(); + Ok(XmlObject::new(node.deep_copy(activation.context.gc_context), activation).into()) +} + pub fn parent<'gc>( activation: &mut Activation<'_, 'gc>, this: Option>,