From 945bce4a851e5f97e114f81c05db5eb8ddb84eff Mon Sep 17 00:00:00 2001 From: Adrian Wielgosik Date: Sun, 29 Aug 2021 14:31:33 +0200 Subject: [PATCH] xml: Use forked quick-xml to support loose entity parsing --- Cargo.lock | 3 +-- core/Cargo.toml | 2 +- core/src/xml/tree.rs | 15 +++++++----- tests/tests/regression_tests.rs | 1 + tests/tests/swfs/avm1/xml_unescaping/Test.as | 23 ++++++++++++++++++ .../tests/swfs/avm1/xml_unescaping/output.txt | 7 ++++++ tests/tests/swfs/avm1/xml_unescaping/test.swf | Bin 0 -> 392 bytes 7 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 tests/tests/swfs/avm1/xml_unescaping/Test.as create mode 100644 tests/tests/swfs/avm1/xml_unescaping/output.txt create mode 100644 tests/tests/swfs/avm1/xml_unescaping/test.swf diff --git a/Cargo.lock b/Cargo.lock index bc033be45..0ae7fc2c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2850,8 +2850,7 @@ checksum = "87dfd5592a8eed7e74f56ad7b125f8234763b805c30f0c7c95c486920026a6ec" [[package]] name = "quick-xml" version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" +source = "git+https://github.com/ruffle-rs/quick-xml?rev=8496365ec1412eb5ba5de350937b6bce352fa0ba#8496365ec1412eb5ba5de350937b6bce352fa0ba" dependencies = [ "memchr", ] diff --git a/core/Cargo.toml b/core/Cargo.toml index 668306381..dddc816f1 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -24,7 +24,7 @@ bitflags = "1.3.2" smallvec = "1.6.1" num-traits = "0.2" num-derive = "0.3" -quick-xml = "0.22.0" +quick-xml = { git = "https://github.com/ruffle-rs/quick-xml", rev = "8496365ec1412eb5ba5de350937b6bce352fa0ba" } downcast-rs = "1.2.0" url = "2.2.2" weak-table = "0.3.0" diff --git a/core/src/xml/tree.rs b/core/src/xml/tree.rs index f682d2c17..543f185f2 100644 --- a/core/src/xml/tree.rs +++ b/core/src/xml/tree.rs @@ -243,13 +243,13 @@ impl<'gc> XmlNode<'gc> { match event { Event::Start(bs) => { - let child = XmlNode::from_start_event(mc, bs, document)?; + let child = XmlNode::from_start_event(mc, bs, document, process_entity)?; self.document().update_idmap(mc, child); self.add_child_to_tree(mc, &mut open_tags, child)?; open_tags.push(child); } Event::Empty(bs) => { - let child = XmlNode::from_start_event(mc, bs, document)?; + let child = XmlNode::from_start_event(mc, bs, document, process_entity)?; self.document().update_idmap(mc, child); self.add_child_to_tree(mc, &mut open_tags, child)?; } @@ -292,16 +292,19 @@ impl<'gc> XmlNode<'gc> { mc: MutationContext<'gc, '_>, bs: BytesStart<'a>, document: XmlDocument<'gc>, + process_entity: bool, ) -> Result { let tag_name = XmlName::from_bytes(bs.name())?; let mut attributes = BTreeMap::new(); for a in bs.attributes() { let attribute = a?; - attributes.insert( - XmlName::from_bytes(attribute.key)?, - String::from_utf8(attribute.value.to_owned().to_vec())?, - ); + let value = if process_entity { + String::from_utf8(attribute.unescaped_value()?.to_owned().to_vec())? + } else { + String::from_utf8(attribute.value.to_owned().to_vec())? + }; + attributes.insert(XmlName::from_bytes(attribute.key)?, value); } Ok(XmlNode(GcCell::allocate( diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index e3db270a1..b7e3d8d86 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -237,6 +237,7 @@ swf_tests! { (xml_ignore_comments, "avm1/xml_ignore_comments", 1), (xml_ignore_white, "avm1/xml_ignore_white", 1), (xml_inspect_doctype, "avm1/xml_inspect_doctype", 1), + (xml_unescaping, "avm1/xml_unescaping", 1), #[ignore] (xml_inspect_xmldecl, "avm1/xml_inspect_xmldecl", 1), (xml_inspect_createmethods, "avm1/xml_inspect_createmethods", 1), (xml_inspect_parsexml, "avm1/xml_inspect_parsexml", 1), diff --git a/tests/tests/swfs/avm1/xml_unescaping/Test.as b/tests/tests/swfs/avm1/xml_unescaping/Test.as new file mode 100644 index 000000000..9650346a2 --- /dev/null +++ b/tests/tests/swfs/avm1/xml_unescaping/Test.as @@ -0,0 +1,23 @@ +// Compile with: +// mtasc -main -header 200:150:30 Test.as -swf test.swf +class Test { + static function main(current) { + +var xml; +xml = new XML("A & ' B"); +trace(xml.firstChild.firstChild.nodeValue); + +xml = new XML(""); +trace(""); +trace(xml.firstChild.attributes.label); + +xml = new XML("A & &thing; B"); +trace(""); +trace(xml.firstChild.firstChild.nodeValue); + +xml = new XML(""); +trace(""); +trace(xml.firstChild.attributes.label); + + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm1/xml_unescaping/output.txt b/tests/tests/swfs/avm1/xml_unescaping/output.txt new file mode 100644 index 000000000..5d94c6a13 --- /dev/null +++ b/tests/tests/swfs/avm1/xml_unescaping/output.txt @@ -0,0 +1,7 @@ +A & ' B + +A & ' B + +A & &thing; B + +A & &thing; B diff --git a/tests/tests/swfs/avm1/xml_unescaping/test.swf b/tests/tests/swfs/avm1/xml_unescaping/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..b3a064c91f18de036ccbf941538d12d43e492171 GIT binary patch literal 392 zcmV;30eAjGS5pUt0ssJb+KiIRO2a@DhEFbSQZFqQAqYi6g@7AfxRPGef*{y5*dp%2 zv>n@EnuKHu`UG~>Wp=)T4Y?(57%>1Cs{_?dI^oqw2r@&v*cK;{GBSb(;;q$`&N zx@>_;BY#Mh?rg`g(eM$CaeUUtF@a_NlL7Yp9SXoZ&e#hE$b&EnNI;%L3{&L#P#qzH z>ZWd>X;{&XlZ(rW-m0GSF5Gu+;K7Yz(w?~92>f7#?~pgc>6GrF0rqO;t>JS0cN`EQ zkvo_X90O-pr|AZnxc+$UtZmB`u`)D!JxuH<2(LUejv*02g;KHjDneFZg;3(Hg~}3= zj;OrQ6uOBFGN__O3qeZ@X>q`UlTSe$&Y}qW1l}OYfhsF3H#O6wu*6|W&05ShRmCzG zrfy>NL(W)-cew7R@ZKNrhV%Y^ox4c^I4jD6BC(l#O@oHiqT6|iUb53Sdu^v