Skip to content

Commit

Permalink
avm2: Reimplement XML.appendChild in terms of [[Get]] and [[Put]]
Browse files Browse the repository at this point in the history
  • Loading branch information
evilpie authored and Lord-McSweeney committed Oct 28, 2023
1 parent 7cec9ed commit 08d6a7b
Showing 1 changed file with 16 additions and 58 deletions.
74 changes: 16 additions & 58 deletions core/src/avm2/globals/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,65 +430,23 @@ pub fn append_child<'gc>(
let child = args.get_value(0);
let child = crate::avm2::e4x::maybe_escape_child(activation, child)?;

if let Some(child) = child.as_object().and_then(|o| o.as_xml_object()) {
xml.node()
.append_child(activation.context.gc_context, *child.node())?;
} else if let Some(list) = child.as_object().and_then(|o| o.as_xml_list_object()) {
for child in &*list.children() {
xml.node()
.append_child(activation.context.gc_context, *child.node())?;
}
} else {
// Appending a non-XML/XMLList object
let (last_child_namespace, last_child_name) =
if let E4XNodeKind::Element { children, .. } = &*xml.node().kind() {
let num_children = children.len();

match num_children {
0 => (None, None),
_ => (
children[num_children - 1].namespace(),
children[num_children - 1].local_name(),
),
}
} else {
// FIXME - figure out exactly when appending is allowed in FP,
// and throw the proper AVM error.
return Err(Error::RustError(
format!(
"Cannot append child {child:?} to node {:?}",
xml.node().kind()
)
.into(),
));
};

let text = child.coerce_to_string(activation)?;
if let Some(last_child_name) = last_child_name {
let element_node = E4XNode::element(
activation.context.gc_context,
last_child_namespace,
last_child_name,
Some(*xml.node()),
); // Creating an element requires passing a parent node, unlike creating a text node

let text_node = E4XNode::text(activation.context.gc_context, text, None);

element_node
.append_child(activation.context.gc_context, text_node)
.expect("Appending to an element node should succeed");

xml.node()
.append_child(activation.context.gc_context, element_node)?;
} else {
let node = E4XNode::text(activation.context.gc_context, text, None);
// The text node will be parented in the append_child operation

xml.node()
.append_child(activation.context.gc_context, node)?;
}
};
// 1. Let children be the result of calling the [[Get]] method of x with argument "*"
let name = Multiname::any(activation.gc());
let children = xml.get_property_local(&name, activation)?;

// 2. Call the [[Put]] method of children with arguments children.[[Length]] and child
let xml_list = children
.as_object()
.and_then(|o| o.as_xml_list_object())
.expect("Should have an XMLList");
let length = xml_list.length();
let name = Multiname::new(
activation.avm2().public_namespace,
AvmString::new_utf8(activation.context.gc_context, length.to_string()),
);
xml_list.set_property_local(&name, child, activation)?;

// 3. Return x
Ok(this.into())
}

Expand Down

0 comments on commit 08d6a7b

Please sign in to comment.