avm2: Throw TypeError when trying to parse malformed XML
Scratch detects if a string is valid XML by trying to construct an XML object, and catching the thrown error.
This commit is contained in:
parent
a99b30927f
commit
2d1da4d18e
|
@ -11,7 +11,9 @@ use quick_xml::{
|
||||||
|
|
||||||
use crate::{avm2::TObject, xml::custom_unescape};
|
use crate::{avm2::TObject, xml::custom_unescape};
|
||||||
|
|
||||||
use super::{object::E4XOrXml, string::AvmString, Activation, Error, Multiname, Value};
|
use super::{
|
||||||
|
error::type_error, object::E4XOrXml, string::AvmString, Activation, Error, Multiname, Value,
|
||||||
|
};
|
||||||
use crate::string::{WStr, WString};
|
use crate::string::{WStr, WString};
|
||||||
|
|
||||||
/// The underlying XML node data, based on E4XNode in avmplus
|
/// The underlying XML node data, based on E4XNode in avmplus
|
||||||
|
@ -39,6 +41,17 @@ impl<'gc> Debug for E4XNodeData<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn malformed_element<'gc>(activation: &mut Activation<'_, 'gc>) -> Error<'gc> {
|
||||||
|
Error::AvmError(
|
||||||
|
type_error(
|
||||||
|
activation,
|
||||||
|
"Error #1090: XML parser failure: element is malformed.",
|
||||||
|
1090,
|
||||||
|
)
|
||||||
|
.expect("Failed to construct XML TypeError"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Collect, Debug)]
|
#[derive(Collect, Debug)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub enum E4XNodeKind<'gc> {
|
pub enum E4XNodeKind<'gc> {
|
||||||
|
@ -365,13 +378,14 @@ impl<'gc> E4XNode<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let event = parser.read_event().map_err(|error| {
|
let event = parser
|
||||||
Error::RustError(format!("XML parsing error: {error:?}").into())
|
.read_event()
|
||||||
})?;
|
.map_err(|_| malformed_element(activation))?;
|
||||||
|
|
||||||
match &event {
|
match &event {
|
||||||
Event::Start(bs) => {
|
Event::Start(bs) => {
|
||||||
let child = E4XNode::from_start_event(activation, bs, parser.decoder())?;
|
let child = E4XNode::from_start_event(activation, bs, parser.decoder())
|
||||||
|
.map_err(|_| malformed_element(activation))?;
|
||||||
|
|
||||||
if let Some(current_tag) = open_tags.last_mut() {
|
if let Some(current_tag) = open_tags.last_mut() {
|
||||||
current_tag.append_child(activation.context.gc_context, child)?;
|
current_tag.append_child(activation.context.gc_context, child)?;
|
||||||
|
@ -380,7 +394,8 @@ impl<'gc> E4XNode<'gc> {
|
||||||
depth += 1;
|
depth += 1;
|
||||||
}
|
}
|
||||||
Event::Empty(bs) => {
|
Event::Empty(bs) => {
|
||||||
let node = E4XNode::from_start_event(activation, bs, parser.decoder())?;
|
let node = E4XNode::from_start_event(activation, bs, parser.decoder())
|
||||||
|
.map_err(|_| malformed_element(activation))?;
|
||||||
push_childless_node(node, &mut open_tags, &mut top_level, depth, activation)?;
|
push_childless_node(node, &mut open_tags, &mut top_level, depth, activation)?;
|
||||||
}
|
}
|
||||||
Event::End(_) => {
|
Event::End(_) => {
|
||||||
|
@ -392,7 +407,9 @@ impl<'gc> E4XNode<'gc> {
|
||||||
}
|
}
|
||||||
Event::Text(bt) => {
|
Event::Text(bt) => {
|
||||||
handle_text_cdata(
|
handle_text_cdata(
|
||||||
custom_unescape(bt, parser.decoder())?.as_bytes(),
|
custom_unescape(bt, parser.decoder())
|
||||||
|
.map_err(|_| malformed_element(activation))?
|
||||||
|
.as_bytes(),
|
||||||
ignore_white,
|
ignore_white,
|
||||||
&mut open_tags,
|
&mut open_tags,
|
||||||
&mut top_level,
|
&mut top_level,
|
||||||
|
@ -419,7 +436,8 @@ impl<'gc> E4XNode<'gc> {
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let text = custom_unescape(bt, parser.decoder())?;
|
let text = custom_unescape(bt, parser.decoder())
|
||||||
|
.map_err(|_| malformed_element(activation))?;
|
||||||
let text =
|
let text =
|
||||||
AvmString::new_utf8_bytes(activation.context.gc_context, text.as_bytes());
|
AvmString::new_utf8_bytes(activation.context.gc_context, text.as_bytes());
|
||||||
let kind = match event {
|
let kind = match event {
|
||||||
|
|
|
@ -305,11 +305,3 @@ impl<'gc> From<ruffle_render::error::Error> for Error<'gc> {
|
||||||
Error::RustError(val.into())
|
Error::RustError(val.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - Remove this, and convert `quick_xml` errors into AVM errors,
|
|
||||||
// specific to the XML method that was original invoked.
|
|
||||||
impl<'gc> From<quick_xml::Error> for Error<'gc> {
|
|
||||||
fn from(val: quick_xml::Error) -> Error<'gc> {
|
|
||||||
Error::RustError(val.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -69,6 +69,13 @@
|
||||||
trace("Caught error: " + e);
|
trace("Caught error: " + e);
|
||||||
trace(e.errorID);
|
trace(e.errorID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
trace(new XML("<Hello<"));
|
||||||
|
} catch (e) {
|
||||||
|
trace("Caught parsing error: " + e);
|
||||||
|
trace(e.errorID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,3 +19,5 @@ castCopy equal: true
|
||||||
ctorCopy equal: false
|
ctorCopy equal: false
|
||||||
Caught error: TypeError: Error #1088: The markup in the document following the root element must be well-formed.
|
Caught error: TypeError: Error #1088: The markup in the document following the root element must be well-formed.
|
||||||
1088
|
1088
|
||||||
|
Caught parsing error: TypeError: Error #1090: XML parser failure: element is malformed.
|
||||||
|
1090
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue