Promote bytes to signed representation before pushing.

For whatever reason, `pushbyte` appears to be processed as a *signed* byte, despite the clear wording of "*byte_value* is an unsigned byte" in avm2overview.pdf. I guess it's supposed to be manually converted and promoted in this manner.
This commit is contained in:
David Wendt 2020-06-23 23:43:30 -04:00 committed by Mike Welsh
parent 736a94a244
commit 4c1489a814
2 changed files with 28 additions and 40 deletions

View File

@ -475,7 +475,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Op::NewClass { index } => self.op_new_class(method, index), Op::NewClass { index } => self.op_new_class(method, index),
Op::CoerceA => self.op_coerce_a(), Op::CoerceA => self.op_coerce_a(),
Op::ConvertB => self.op_convert_b(), Op::ConvertB => self.op_convert_b(),
Op::ConvertD => self.op_convert_d(context), Op::ConvertD => self.op_convert_d(),
Op::Jump { offset } => self.op_jump(offset, reader), Op::Jump { offset } => self.op_jump(offset, reader),
Op::IfTrue { offset } => self.op_if_true(offset, reader), Op::IfTrue { offset } => self.op_if_true(offset, reader),
Op::IfFalse { offset } => self.op_if_false(offset, reader), Op::IfFalse { offset } => self.op_if_false(offset, reader),
@ -526,7 +526,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} }
fn op_push_byte(&mut self, value: u8) -> Result<FrameControl<'gc>, Error> { fn op_push_byte(&mut self, value: u8) -> Result<FrameControl<'gc>, Error> {
self.context.avm2.push(value); //TODO: Adobe Animate CC appears to generate signed byte values, and
//JPEXS appears to take them.
self.context.avm2.push(value as i8 as f64);
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
@ -1317,13 +1319,10 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }
fn op_convert_d( fn op_convert_d(&mut self) -> Result<FrameControl<'gc>, Error> {
&mut self, let value = self.context.avm2.pop().coerce_to_number(self)?;
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error> {
let value = self.avm2.pop().coerce_to_number(self, context)?;
self.avm2.push(Value::Number(value)); self.context.avm2.push(Value::Number(value));
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }

View File

@ -7,7 +7,6 @@ use crate::avm2::object::{Object, TObject};
use crate::avm2::script::TranslationUnit; use crate::avm2::script::TranslationUnit;
use crate::avm2::string::AvmString; use crate::avm2::string::AvmString;
use crate::avm2::Error; use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, MutationContext}; use gc_arena::{Collect, MutationContext};
use std::f64::NAN; use std::f64::NAN;
use swf::avm2::types::{DefaultValue as AbcDefaultValue, Index}; use swf::avm2::types::{DefaultValue as AbcDefaultValue, Index};
@ -293,21 +292,17 @@ impl<'gc> Value<'gc> {
pub fn coerce_to_primitive( pub fn coerce_to_primitive(
&self, &self,
hint: Hint, hint: Hint,
activation: &mut Activation<'_, 'gc>, activation: &mut Activation<'_, 'gc, '_>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
match self { match self {
Value::Object(o) if hint == Hint::String => { Value::Object(o) if hint == Hint::String => {
let mut prim = self.clone(); let mut prim = self.clone();
let mut object = *o; let mut object = *o;
if let Value::Object(f) = object.get_property( if let Value::Object(f) =
*o, object.get_property(*o, &QName::dynamic_name("toString"), activation)?
&QName::dynamic_name("toString"), {
activation, prim = f.call(Some(*o), &[], activation, None)?;
context,
)? {
prim = f.call(Some(*o), &[], activation, context, None)?;
} }
if prim.is_primitive() { if prim.is_primitive() {
@ -315,9 +310,9 @@ impl<'gc> Value<'gc> {
} }
if let Value::Object(f) = if let Value::Object(f) =
object.get_property(*o, &QName::dynamic_name("valueOf"), activation, context)? object.get_property(*o, &QName::dynamic_name("valueOf"), activation)?
{ {
prim = f.call(Some(*o), &[], activation, context, None)?; prim = f.call(Some(*o), &[], activation, None)?;
} }
if prim.is_primitive() { if prim.is_primitive() {
@ -331,22 +326,19 @@ impl<'gc> Value<'gc> {
let mut object = *o; let mut object = *o;
if let Value::Object(f) = if let Value::Object(f) =
object.get_property(*o, &QName::dynamic_name("valueOf"), activation, context)? object.get_property(*o, &QName::dynamic_name("valueOf"), activation)?
{ {
prim = f.call(Some(*o), &[], activation, context, None)?; prim = f.call(Some(*o), &[], activation, None)?;
} }
if prim.is_primitive() { if prim.is_primitive() {
return Ok(prim); return Ok(prim);
} }
if let Value::Object(f) = object.get_property( if let Value::Object(f) =
*o, object.get_property(*o, &QName::dynamic_name("toString"), activation)?
&QName::dynamic_name("toString"), {
activation, prim = f.call(Some(*o), &[], activation, None)?;
context,
)? {
prim = f.call(Some(*o), &[], activation, context, None)?;
} }
if prim.is_primitive() { if prim.is_primitive() {
@ -367,11 +359,7 @@ impl<'gc> Value<'gc> {
/// ///
/// Numerical conversions occur according to ECMA-262 3rd Edition's /// Numerical conversions occur according to ECMA-262 3rd Edition's
/// ToNumber algorithm which appears to match AVM2. /// ToNumber algorithm which appears to match AVM2.
pub fn coerce_to_number( pub fn coerce_to_number(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<f64, Error> {
&self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<f64, Error> {
Ok(match self { Ok(match self {
Value::Undefined => f64::NAN, Value::Undefined => f64::NAN,
Value::Null => 0.0, Value::Null => 0.0,
@ -427,13 +415,14 @@ impl<'gc> Value<'gc> {
sign * digits.parse().unwrap_or(f64::NAN) sign * digits.parse().unwrap_or(f64::NAN)
} }
} }
Value::Namespace(ns) => { Value::Namespace(ns) => Value::String(AvmString::new(
Value::String(AvmString::new(context.gc_context, ns.as_uri().to_string())) activation.context.gc_context,
.coerce_to_number(activation, context)? ns.as_uri().to_string(),
} ))
.coerce_to_number(activation)?,
Value::Object(_) => self Value::Object(_) => self
.coerce_to_primitive(Hint::Number, activation, context)? .coerce_to_primitive(Hint::Number, activation)?
.coerce_to_number(activation, context)?, .coerce_to_number(activation)?,
}) })
} }
} }