avm1: Add include_hidden: bool to get_keys()

This commit is contained in:
Nathan Adams 2023-06-05 12:13:14 +02:00
parent 310b03b570
commit afdd617d29
10 changed files with 44 additions and 23 deletions

View File

@ -1022,12 +1022,12 @@ impl<'a, 'gc> Activation<'a, 'gc> {
match object {
Value::MovieClip(_) => {
let ob = object.coerce_to_object(self);
for k in ob.get_keys(self).into_iter().rev() {
for k in ob.get_keys(self, false).into_iter().rev() {
self.stack_push(k.into());
}
}
Value::Object(ob) => {
for k in ob.get_keys(self).into_iter().rev() {
for k in ob.get_keys(self, false).into_iter().rev() {
self.stack_push(k.into());
}
}
@ -1044,11 +1044,11 @@ impl<'a, 'gc> Activation<'a, 'gc> {
if let Value::MovieClip(_) = value {
let object = value.coerce_to_object(self);
for k in object.get_keys(self).into_iter().rev() {
for k in object.get_keys(self, false).into_iter().rev() {
self.stack_push(k.into());
}
} else if let Value::Object(object) = value {
for k in object.get_keys(self).into_iter().rev() {
for k in object.get_keys(self, false).into_iter().rev() {
self.stack_push(k.into());
}
} else {
@ -2445,7 +2445,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
/// WARNING: This does not support user defined virtual properties!
pub fn object_into_form_values(&mut self, object: Object<'gc>) -> IndexMap<String, String> {
let mut form_values = IndexMap::new();
let keys = object.get_keys(self);
let keys = object.get_keys(self, false);
for k in keys {
let v = object.get(k, self);

View File

@ -119,7 +119,7 @@ impl<'a> VariableDumper<'a> {
object: &Object<'gc>,
activation: &mut Activation<'_, 'gc>,
) {
let keys = object.get_keys(activation);
let keys = object.get_keys(activation, false);
if keys.is_empty() {
self.output.push_str(" {}");
} else {
@ -166,7 +166,7 @@ impl<'a> VariableDumper<'a> {
object: &Object<'gc>,
activation: &mut Activation<'_, 'gc>,
) {
let keys = object.get_keys(activation);
let keys = object.get_keys(activation, false);
if keys.is_empty() {
return;
}

View File

@ -171,7 +171,7 @@ fn send<'gc>(
use indexmap::IndexMap;
let mut form_values = IndexMap::new();
let keys = this.get_keys(activation);
let keys = this.get_keys(activation, false);
for k in keys {
let v = this.get(k, activation);
@ -226,7 +226,7 @@ fn to_string<'gc>(
use indexmap::IndexMap;
let mut form_values = IndexMap::new();
let keys = this.get_keys(activation);
let keys = this.get_keys(activation, false);
for k in keys {
let v = this.get(k, activation);

View File

@ -102,7 +102,7 @@ fn recursive_serialize<'gc>(
elements: &mut Vec<Element>,
) {
// Reversed to match flash player ordering
for element_name in obj.get_keys(activation).into_iter().rev() {
for element_name in obj.get_keys(activation, false).into_iter().rev() {
if let Ok(elem) = obj.get(element_name, activation) {
if let Some(v) = serialize_value(activation, elem) {
elements.push(Element::new(element_name.to_utf8_lossy(), v));
@ -439,7 +439,7 @@ pub fn clear<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let data = this.get("data", activation)?.coerce_to_object(activation);
for k in &data.get_keys(activation) {
for k in &data.get_keys(activation, false) {
data.delete(activation, *k);
}

View File

@ -477,8 +477,13 @@ pub trait TObject<'gc>: 'gc + Collect + Into<Object<'gc>> + Clone + Copy {
}
/// Enumerate the object.
fn get_keys(&self, activation: &mut Activation<'_, 'gc>) -> Vec<AvmString<'gc>> {
self.raw_script_object().get_keys(activation)
fn get_keys(
&self,
activation: &mut Activation<'_, 'gc>,
include_hidden: bool,
) -> Vec<AvmString<'gc>> {
self.raw_script_object()
.get_keys(activation, include_hidden)
}
/// Enumerate all interfaces implemented by this object.

View File

@ -444,9 +444,13 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
}
/// Enumerate the object.
fn get_keys(&self, activation: &mut Activation<'_, 'gc>) -> Vec<AvmString<'gc>> {
fn get_keys(
&self,
activation: &mut Activation<'_, 'gc>,
include_hidden: bool,
) -> Vec<AvmString<'gc>> {
let proto_keys = if let Value::Object(proto) = self.proto(activation) {
proto.get_keys(activation)
proto.get_keys(activation, include_hidden)
} else {
Vec::new()
};
@ -461,7 +465,7 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
// Then our own keys.
out_keys.extend(self.0.read().properties.iter().filter_map(move |(k, p)| {
if p.is_enumerable() {
if include_hidden || p.is_enumerable() {
Some(k)
} else {
None
@ -756,7 +760,7 @@ mod tests {
Attribute::DONT_ENUM,
);
let keys: Vec<_> = object.get_keys(activation);
let keys: Vec<_> = object.get_keys(activation, false);
assert_eq!(keys.len(), 2);
assert!(keys.contains(&"stored".into()));
assert!(!keys.contains(&"stored_hidden".into()));

View File

@ -330,11 +330,15 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
false
}
fn get_keys(&self, activation: &mut Activation<'_, 'gc>) -> Vec<AvmString<'gc>> {
fn get_keys(
&self,
activation: &mut Activation<'_, 'gc>,
include_hidden: bool,
) -> Vec<AvmString<'gc>> {
// Keys from the underlying object are listed first, followed by
// child display objects in order from highest depth to lowest depth.
let obj = self.0.read();
let mut keys = obj.base.get_keys(activation);
let mut keys = obj.base.get_keys(activation, include_hidden);
if let Some(ctr) = obj.display_object.as_container() {
// Button/MovieClip children are included in key list.

View File

@ -223,7 +223,11 @@ impl<'gc> TObject<'gc> for SuperObject<'gc> {
false
}
fn get_keys(&self, _activation: &mut Activation<'_, 'gc>) -> Vec<AvmString<'gc>> {
fn get_keys(
&self,
_activation: &mut Activation<'_, 'gc>,
_include_hidden: bool,
) -> Vec<AvmString<'gc>> {
vec![]
}

View File

@ -1980,7 +1980,11 @@ impl<'gc> MovieClip<'gc> {
if let Some(init_object) = init_object {
// AVM1 sets keys in reverse order (compared to enumeration order).
// This behavior is visible to setters, and some SWFs depend on it.
for key in init_object.get_keys(&mut activation).into_iter().rev() {
for key in init_object
.get_keys(&mut activation, false)
.into_iter()
.rev()
{
if let Ok(value) = init_object.get(key, &mut activation) {
let _ = object.set(key, value, &mut activation);
}
@ -2011,7 +2015,7 @@ impl<'gc> MovieClip<'gc> {
self.into(),
);
for key in init_object.get_keys(&mut activation) {
for key in init_object.get_keys(&mut activation, false) {
if let Ok(value) = init_object.get(key, &mut activation) {
let _ = object.set(key, value, &mut activation);
}

View File

@ -141,7 +141,7 @@ impl Value {
.collect();
Value::List(values?)
} else {
let keys = object.get_keys(activation);
let keys = object.get_keys(activation, false);
let mut values = BTreeMap::new();
for key in keys {
let value = object.get(key, activation)?;