Filter non-AS2 compatible nodes from toString output, and add non-SWF tests for XML filtering.

This commit is contained in:
David Wendt 2019-12-31 14:25:12 -07:00
parent ce1b958abb
commit 2c790f1d41
3 changed files with 75 additions and 9 deletions

View File

@ -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);
}

View File

@ -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 = "<test><!-- Comment -->This is a text node</test>";
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 = "<test><!-- Comment -->This is a text node</test>";
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!("<test>This is a text node</test>", result);
})
}

View File

@ -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<W>(self, writer: &mut Writer<W>) -> 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<W, F>(self, writer: &mut Writer<W>, 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),
@ -1214,10 +1240,8 @@ impl<'gc> XMLNode<'gc> {
)),
}?;
if let Some(children) = self.children() {
for child in children {
child.write_node_to_event_writer(writer)?;
}
child.write_node_to_event_writer(writer, filter)?;
}
match &*self.0.read() {