diff --git a/core/src/avm1/globals/xml.rs b/core/src/avm1/globals/xml.rs index 5ba75f4e8..9350f7fba 100644 --- a/core/src/avm1/globals/xml.rs +++ b/core/src/avm1/globals/xml.rs @@ -199,7 +199,7 @@ pub fn xmlnode_to_string<'gc>( if let Some(node) = this.as_xml_node() { let mut writer = Writer::new(Cursor::new(&mut result)); - node.write_node_to_event_writer(&mut writer); + node.write_node_to_event_writer(&mut writer, &mut is_as2_compatible); } Ok(String::from_utf8(result) @@ -669,7 +669,7 @@ pub fn create_xml_proto<'gc>( if let Some(doctype) = node.document().doctype() { let mut result = Vec::new(); let mut writer = Writer::new(Cursor::new(&mut result)); - if let Err(e) = doctype.write_node_to_event_writer(&mut writer) { + if let Err(e) = doctype.write_node_to_event_writer(&mut writer, &mut |_| true) { log::warn!("Error occured when serializing DOCTYPE: {}", e); } diff --git a/core/src/xml/tests.rs b/core/src/xml/tests.rs index 32a6b251d..f29f0f555 100644 --- a/core/src/xml/tests.rs +++ b/core/src/xml/tests.rs @@ -2,7 +2,9 @@ use crate::xml; use crate::xml::{XMLDocument, XMLName}; +use quick_xml::Writer; use gc_arena::rootless_arena; +use std::io::Cursor; /// Tests very basic parsing of a single-element document. #[test] @@ -70,3 +72,43 @@ fn double_ended_children() { assert!(roots.next_back().is_none()); }) } + +/// Tests round-trip XML writing behavior. +#[test] +fn round_trip_tostring() { + let test_string = "This is a text node"; + + rootless_arena(|mc| { + let xml = XMLDocument::new(mc); + xml.as_node() + .replace_with_str(mc, test_string) + .expect("Parsed document"); + + let mut buf = Vec::new(); + let mut writer = Writer::new(Cursor::new(&mut buf)); + xml.as_node().write_node_to_event_writer(&mut writer, &mut |_| true).expect("Successful toString"); + let result = String::from_utf8(buf).expect("Valid UTF-8"); + + assert_eq!(test_string, result); + }) +} + +/// Tests filtered XML writing behavior. +#[test] +fn round_trip_filtered_tostring() { + let test_string = "This is a text node"; + + rootless_arena(|mc| { + let xml = XMLDocument::new(mc); + xml.as_node() + .replace_with_str(mc, test_string) + .expect("Parsed document"); + + let mut buf = Vec::new(); + let mut writer = Writer::new(Cursor::new(&mut buf)); + xml.as_node().write_node_to_event_writer(&mut writer, &mut |node| !node.is_comment()).expect("Successful toString"); + let result = String::from_utf8(buf).expect("Valid UTF-8"); + + assert_eq!("This is a text node", result); + }) +} \ No newline at end of file diff --git a/core/src/xml/tree.rs b/core/src/xml/tree.rs index c38f95c83..ac8e61180 100644 --- a/core/src/xml/tree.rs +++ b/core/src/xml/tree.rs @@ -983,6 +983,15 @@ impl<'gc> XMLNode<'gc> { } } + /// Check if this XML node constitutes text. + #[allow(dead_code)] + pub fn is_comment(self) -> bool { + match &*self.0.read() { + XMLNodeData::Comment { .. } => true, + _ => false, + } + } + /// Check if this XML node constitutes a DOCTYPE declaration pub fn is_doctype(self) -> bool { match &*self.0.read() { @@ -1168,11 +1177,28 @@ impl<'gc> XMLNode<'gc> { } } - pub fn write_node_to_event_writer(self, writer: &mut Writer) -> Result<(), Error> + /// Write the contents of this node, including it's children, to the given + /// writer. + /// + /// The given filter function allows filtering specific children out of the + /// resulting write stream. It will be called at least once for each node + /// encountered in the tree (other than this one) if specified; only nodes + /// that yield `true` shall be printed. + pub fn write_node_to_event_writer(self, writer: &mut Writer, filter: &mut F) -> Result<(), Error> where W: Write, + F: FnMut(XMLNode<'gc>) -> bool { - let children_len = self.children_len(); + let mut children = Vec::new(); + if let Some(my_children) = self.children() { + for child in my_children { + if filter(child) { + children.push(child) + } + } + } + + let children_len = children.len(); match &*self.0.read() { XMLNodeData::DocumentRoot { .. } => Ok(0), @@ -1213,11 +1239,9 @@ impl<'gc> XMLNode<'gc> { BytesText::from_plain_str(contents.as_str()), )), }?; - - if let Some(children) = self.children() { - for child in children { - child.write_node_to_event_writer(writer)?; - } + + for child in children { + child.write_node_to_event_writer(writer, filter)?; } match &*self.0.read() {