diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index f6ac046b4..d88ca3b18 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -176,6 +176,8 @@ pub fn create_globals<'gc>( let xmlnode_proto: Object<'gc> = xml::create_xmlnode_proto(gc_context, object_proto, function_proto); + let xml_proto: Object<'gc> = xml::create_xml_proto(gc_context, xmlnode_proto, function_proto); + //TODO: These need to be constructors and should also set `.prototype` on each one let object = ScriptObject::function( gc_context, @@ -226,6 +228,12 @@ pub fn create_globals<'gc>( Some(function_proto), Some(xmlnode_proto), ); + let xml = ScriptObject::function( + gc_context, + Executable::Native(xml::xml_constructor), + Some(function_proto), + Some(xml_proto), + ); let listeners = SystemListeners::new(gc_context, Some(array_proto)); @@ -238,6 +246,7 @@ pub fn create_globals<'gc>( globals.define_value(gc_context, "Sound", sound.into(), EnumSet::empty()); globals.define_value(gc_context, "TextField", text_field.into(), EnumSet::empty()); globals.define_value(gc_context, "XMLNode", xmlnode.into(), EnumSet::empty()); + globals.define_value(gc_context, "XML", xml.into(), EnumSet::empty()); globals.force_set_function( "Number", number, diff --git a/core/src/avm1/globals/xml.rs b/core/src/avm1/globals/xml.rs index 4f7a4d6c6..ee41fead9 100644 --- a/core/src/avm1/globals/xml.rs +++ b/core/src/avm1/globals/xml.rs @@ -3,7 +3,7 @@ use crate::avm1::return_value::ReturnValue; use crate::avm1::script_object::ScriptObject; use crate::avm1::{Avm1, Error, Object, TObject, UpdateContext, Value}; -use crate::xml::XMLNode; +use crate::xml::{XMLDocument, XMLNode}; use gc_arena::MutationContext; use std::mem::swap; @@ -16,14 +16,14 @@ pub fn xmlnode_constructor<'gc>( ) -> Result, Error> { match ( args.get(0).map(|v| v.as_number(avm, ac).map(|v| v as u32)), - args.get(1).map(|v| v.as_string()), + args.get(1).map(|v| v.clone().coerce_to_string(avm, ac)), this.as_xml_node(), ) { - (Some(Ok(1)), Some(Ok(strval)), Some(ref mut this_node)) => { + (Some(Ok(1)), Some(Ok(ref strval)), Some(ref mut this_node)) => { let mut xmlelement = XMLNode::new_text(ac.gc_context, strval); swap(&mut xmlelement, this_node); } - (Some(Ok(3)), Some(Ok(strval)), Some(ref mut this_node)) => { + (Some(Ok(3)), Some(Ok(ref strval)), Some(ref mut this_node)) => { let mut xmlelement = XMLNode::new_element(ac.gc_context, strval)?; swap(&mut xmlelement, this_node); } @@ -44,3 +44,42 @@ pub fn create_xmlnode_proto<'gc>( xmlnode_proto.into() } + +/// XML (document) constructor +pub fn xml_constructor<'gc>( + avm: &mut Avm1<'gc>, + ac: &mut UpdateContext<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error> { + match ( + args.get(0).map(|v| v.clone().coerce_to_string(avm, ac)), + this.as_xml_document(), + ) { + (Some(Ok(ref string)), Some(ref mut this_doc)) => { + let mut xmldoc = XMLDocument::from_str(ac.gc_context, string)?; + + swap(&mut xmldoc, this_doc); + } + (None, Some(ref mut this_doc)) => { + let mut emptydoc = XMLDocument::new(ac.gc_context); + + swap(&mut emptydoc, this_doc); + } + //Non-string argument or not an XML document + _ => {} + }; + + Ok(Value::Undefined.into()) +} + +/// Construct the prototype for `XML`. +pub fn create_xml_proto<'gc>( + gc_context: MutationContext<'gc, '_>, + proto: Object<'gc>, + _fn_proto: Object<'gc>, +) -> Object<'gc> { + let xml_proto = ScriptObject::object(gc_context, Some(proto)); + + xml_proto.into() +}