From 4cfa3253d59c28d1690b593a775a4e1ccb18422a Mon Sep 17 00:00:00 2001 From: David Wendt Date: Fri, 5 Nov 2021 22:02:46 -0400 Subject: [PATCH] avm2: Impl `Proxy`'s enumeration-related methods. --- core/src/avm2/activation.rs | 8 ++--- core/src/avm2/object.rs | 27 +++++++++------- core/src/avm2/object/array_object.rs | 26 +++++++++++---- core/src/avm2/object/dictionary_object.rs | 25 +++++++++++---- core/src/avm2/object/proxy_object.rs | 39 +++++++++++++++++++++++ core/src/avm2/object/vector_object.rs | 23 +++++++++---- 6 files changed, 115 insertions(+), 33 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 4acc886e7..29506d596 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -2442,7 +2442,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let cur_index = self.context.avm2.pop().coerce_to_u32(self)?; let object = self.context.avm2.pop().coerce_to_object(self)?; - if let Some(next_index) = object.get_next_enumerant(cur_index) { + if let Some(next_index) = object.get_next_enumerant(cur_index, self)? { self.context.avm2.push(next_index); } else { self.context.avm2.push(0.0); @@ -2463,7 +2463,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { ); while let Some(cur_object) = object { - if let Some(index) = cur_object.get_next_enumerant(cur_index) { + if let Some(index) = cur_object.get_next_enumerant(cur_index, self)? { cur_index = index; break; } else { @@ -2491,9 +2491,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { let cur_index = self.context.avm2.pop().coerce_to_number(self)?; let object = self.context.avm2.pop().coerce_to_object(self)?; - let name = object.get_enumerant_name(cur_index as u32); + let name = object.get_enumerant_name(cur_index as u32, self)?; - self.context.avm2.push(name.unwrap_or(Value::Undefined)); + self.context.avm2.push(name); Ok(FrameControl::Continue) } diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index d4ad5e8e4..10b299628 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -794,10 +794,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// Repeated calls to this function with prior return values must /// eventually return `None`. Furthermore, returning `0`, while valid, is /// treated by AVM2 code as signalling `None`. - fn get_next_enumerant(self, last_index: u32) -> Option { + fn get_next_enumerant( + self, + last_index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { let base = self.base(); - base.get_next_enumerant(last_index) + Ok(base.get_next_enumerant(last_index)) } /// Retrieve a given enumerable name by index. @@ -806,10 +810,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// `get_next_enumerant`. Only enumerants returned by that function are /// valid here. A value of `None` indicates that no enumerant with that /// index exists. - fn get_enumerant_name(self, index: u32) -> Option> { + fn get_enumerant_name( + self, + index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { let base = self.base(); - base.get_enumerant_name(index) + Ok(base.get_enumerant_name(index).unwrap_or(Value::Undefined)) } /// Retrieve a given enumerable value by index. @@ -821,13 +829,10 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy index: u32, activation: &mut Activation<'_, 'gc, '_>, ) -> Result, Error> { - let name = self.get_enumerant_name(index); - if let Some(name) = name { - let name = name.coerce_to_string(activation)?; - Ok(self.get_property(self.into(), &QName::dynamic_name(name).into(), activation)?) - } else { - Ok(Value::Undefined) - } + let name = self + .get_enumerant_name(index, activation)? + .coerce_to_string(activation)?; + self.get_property(self.into(), &QName::dynamic_name(name).into(), activation) } /// Determine if a property is currently enumerable. diff --git a/core/src/avm2/object/array_object.rs b/core/src/avm2/object/array_object.rs index 1b5fb19d0..657cc2d70 100644 --- a/core/src/avm2/object/array_object.rs +++ b/core/src/avm2/object/array_object.rs @@ -199,24 +199,38 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> { self.0.read().base.resolve_any(local_name) } - fn get_next_enumerant(self, last_index: u32) -> Option { + fn get_next_enumerant( + self, + last_index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { let read = self.0.read(); let last_enumerant = read.base.get_last_enumerant(); let array_length = read.array.length() as u32; if last_index < last_enumerant + array_length { - Some(last_index.saturating_add(1)) + Ok(Some(last_index.saturating_add(1))) } else { - None + Ok(None) } } - fn get_enumerant_name(self, index: u32) -> Option> { + fn get_enumerant_name( + self, + index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { let arr_len = self.0.read().array.length() as u32; if arr_len >= index { - index.checked_sub(1).map(|index| index.into()) + Ok(index + .checked_sub(1) + .map(|index| index.into()) + .unwrap_or(Value::Undefined)) } else { - self.base().get_enumerant_name(index - arr_len) + Ok(self + .base() + .get_enumerant_name(index - arr_len) + .unwrap_or(Value::Undefined)) } } diff --git a/core/src/avm2/object/dictionary_object.rs b/core/src/avm2/object/dictionary_object.rs index 595ac03d1..f077adfe1 100644 --- a/core/src/avm2/object/dictionary_object.rs +++ b/core/src/avm2/object/dictionary_object.rs @@ -111,32 +111,45 @@ impl<'gc> TObject<'gc> for DictionaryObject<'gc> { Some(self) } - fn get_next_enumerant(self, last_index: u32) -> Option { + fn get_next_enumerant( + self, + last_index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { let read = self.0.read(); let last_enumerant = read.base.get_last_enumerant(); let object_space_length = read.object_space.keys().len() as u32; if last_index < last_enumerant + object_space_length { - Some(last_index.saturating_add(1)) + Ok(Some(last_index.saturating_add(1))) } else { - None + Ok(None) } } - fn get_enumerant_name(self, index: u32) -> Option> { + fn get_enumerant_name( + self, + index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { let read = self.0.read(); let last_enumerant = read.base.get_last_enumerant(); if index < last_enumerant { - read.base.get_enumerant_name(index) + Ok(read + .base + .get_enumerant_name(index) + .unwrap_or(Value::Undefined)) } else { let object_space_index = index.saturating_sub(last_enumerant); - read.object_space + Ok(read + .object_space .keys() .nth(object_space_index as usize) .cloned() .map(|v| v.into()) + .unwrap_or(Value::Undefined)) } } } diff --git a/core/src/avm2/object/proxy_object.rs b/core/src/avm2/object/proxy_object.rs index 4821eabee..8dd572e39 100644 --- a/core/src/avm2/object/proxy_object.rs +++ b/core/src/avm2/object/proxy_object.rs @@ -221,4 +221,43 @@ impl<'gc> TObject<'gc> for ProxyObject<'gc> { )? .coerce_to_boolean()) } + + fn get_next_enumerant( + self, + last_index: u32, + activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { + Ok(Some( + self.call_property( + &QName::new(Namespace::Namespace(NS_FLASH_PROXY.into()), "nextNameIndex").into(), + &[last_index.into()], + activation, + )? + .coerce_to_u32(activation)?, + )) + } + + fn get_enumerant_name( + self, + index: u32, + activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { + self.call_property( + &QName::new(Namespace::Namespace(NS_FLASH_PROXY.into()), "nextName").into(), + &[index.into()], + activation, + ) + } + + fn get_enumerant_value( + self, + index: u32, + activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { + self.call_property( + &QName::new(Namespace::Namespace(NS_FLASH_PROXY.into()), "nextValue").into(), + &[index.into()], + activation, + ) + } } diff --git a/core/src/avm2/object/vector_object.rs b/core/src/avm2/object/vector_object.rs index f91b12e44..86de52a07 100644 --- a/core/src/avm2/object/vector_object.rs +++ b/core/src/avm2/object/vector_object.rs @@ -227,19 +227,30 @@ impl<'gc> TObject<'gc> for VectorObject<'gc> { self.0.read().base.resolve_any(local_name) } - fn get_next_enumerant(self, last_index: u32) -> Option { + fn get_next_enumerant( + self, + last_index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { if last_index < self.0.read().vector.length() as u32 { - Some(last_index.saturating_add(1)) + Ok(Some(last_index.saturating_add(1))) } else { - None + Ok(None) } } - fn get_enumerant_name(self, index: u32) -> Option> { + fn get_enumerant_name( + self, + index: u32, + _activation: &mut Activation<'_, 'gc, '_>, + ) -> Result, Error> { if self.0.read().vector.length() as u32 >= index { - index.checked_sub(1).map(|index| index.into()) + Ok(index + .checked_sub(1) + .map(|index| index.into()) + .unwrap_or(Value::Undefined)) } else { - None + Ok("".into()) } }