avm2: Implement XML construction from XML and XMLList objects
This commit is contained in:
parent
79dfeaf715
commit
b140ce6d97
|
@ -9,6 +9,8 @@ use quick_xml::{
|
|||
Reader,
|
||||
};
|
||||
|
||||
use crate::avm2::{error::type_error, TObject};
|
||||
|
||||
use super::{object::E4XOrXml, string::AvmString, Activation, Error, Multiname, Value};
|
||||
use crate::string::{WStr, WString};
|
||||
|
||||
|
@ -117,14 +119,29 @@ impl<'gc> E4XNode<'gc> {
|
|||
/// The caller is responsible for validating that the number of top-level nodes
|
||||
/// is correct (for XML, there should be exactly one.)
|
||||
pub fn parse(
|
||||
value: Value<'gc>,
|
||||
mut value: Value<'gc>,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<Vec<Self>, Error<'gc>> {
|
||||
let string = match value {
|
||||
let string = match &value {
|
||||
// The docs claim that this throws a TypeError, but it actually doesn't
|
||||
Value::Null | Value::Undefined => AvmString::default(),
|
||||
// The docs claim that only String, Number or Boolean are accepted, but that's also a lie
|
||||
value => value.coerce_to_string(activation)?,
|
||||
val => {
|
||||
if let Some(obj) = val.as_object() {
|
||||
if let Some(xml) = obj.as_xml_object() {
|
||||
value = xml.call_public_property("toXMLString", &[], activation)?;
|
||||
} else if let Some(list) = obj.as_xml_list_object() {
|
||||
if list.length() == 1 {
|
||||
value = list.children_mut(activation.context.gc_context)[0]
|
||||
.get_or_create_xml(activation)
|
||||
.call_public_property("toXMLString", &[], activation)?;
|
||||
} else {
|
||||
return Err(Error::AvmError(type_error(activation, "Error #1088: The markup in the document following the root element must be well-formed.", 1088)?));
|
||||
}
|
||||
}
|
||||
}
|
||||
value.coerce_to_string(activation)?
|
||||
}
|
||||
};
|
||||
|
||||
let data_utf8 = string.to_utf8_lossy();
|
||||
|
@ -342,15 +359,9 @@ impl<'gc> E4XNode<'gc> {
|
|||
|
||||
pub fn xml_to_xml_string(
|
||||
&self,
|
||||
_activation: &mut Activation<'_, 'gc>,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<AvmString<'gc>, Error<'gc>> {
|
||||
match &self.0.read().kind {
|
||||
E4XNodeKind::Text(text) => Ok(*text),
|
||||
E4XNodeKind::Element { .. } => {
|
||||
Err(format!("XML.toXMLString(): Not yet implemented element {:?}", self).into())
|
||||
}
|
||||
other => Err(format!("XML.toXMLString(): Not yet implemented for {other:?}").into()),
|
||||
}
|
||||
return to_xml_string(E4XOrXml::E4X(*self), activation);
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> Ref<'_, E4XNodeKind<'gc>> {
|
||||
|
|
|
@ -15,8 +15,8 @@ pub fn init<'gc>(
|
|||
let this = this.unwrap().as_xml_object().unwrap();
|
||||
let value = args[0];
|
||||
|
||||
match E4XNode::parse(value, activation) {
|
||||
Ok(nodes) => {
|
||||
let nodes = E4XNode::parse(value, activation)?;
|
||||
|
||||
let node = match nodes.as_slice() {
|
||||
// XML defaults to an empty text node when nothing was parsed
|
||||
[] => E4XNode::text(activation.context.gc_context, AvmString::default()),
|
||||
|
@ -32,13 +32,6 @@ pub fn init<'gc>(
|
|||
}
|
||||
};
|
||||
this.set_node(activation.context.gc_context, node);
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(Error::RustError(
|
||||
format!("Failed to parse XML: {e:?}").into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
|
||||
public function Main() {
|
||||
XML.prettyPrinting = false;
|
||||
|
||||
var byteArray: ByteArray = new ByteArray();
|
||||
byteArray.writeUTFBytes("<foo><bar>test</bar></foo>");
|
||||
byteArray.position = 0;
|
||||
|
@ -20,6 +22,30 @@
|
|||
objWithToString.toString = function() { return "<foo><bar>test</bar></foo>"; };
|
||||
trace("// new XML(objWithToString).bar");
|
||||
trace(new XML(objWithToString).bar);
|
||||
|
||||
var xmlObj = <outer></outer>;
|
||||
var xmlCopy = new XML(xmlObj);
|
||||
trace("xmlCopy().toXMLString(): " + xmlCopy.toXMLString());
|
||||
trace("xmlObj === xmlCopy: " + (xmlObj === xmlCopy));
|
||||
|
||||
var emptyList = new XMLList();
|
||||
try {
|
||||
new XML(emptyList);
|
||||
} catch (e) {
|
||||
trace("Caught error: " + e);
|
||||
trace(e.errorID);
|
||||
}
|
||||
|
||||
var singleList = new XMLList("<outer><inner>Hello</inner><second>World</second></outer>");
|
||||
trace("new XML(singleList): " + new XML(singleList));
|
||||
|
||||
var multiList = new XMLList("<first>Hello</first><second>World</second>");
|
||||
try {
|
||||
new XML(multiList);
|
||||
} catch (e) {
|
||||
trace("Caught error: " + e);
|
||||
trace(e.errorID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,3 +3,10 @@ test
|
|||
|
||||
// new XML(objWithToString).bar
|
||||
test
|
||||
xmlCopy().toXMLString(): <outer/>
|
||||
xmlObj === xmlCopy: false
|
||||
Caught error: TypeError: Error #1088: The markup in the document following the root element must be well-formed.
|
||||
1088
|
||||
new XML(singleList): <outer><inner>Hello</inner><second>World</second></outer>
|
||||
Caught error: TypeError: Error #1088: The markup in the document following the root element must be well-formed.
|
||||
1088
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue