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:
parent
736a94a244
commit
4c1489a814
|
@ -475,7 +475,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
Op::NewClass { index } => self.op_new_class(method, index),
|
||||
Op::CoerceA => self.op_coerce_a(),
|
||||
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::IfTrue { offset } => self.op_if_true(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> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -1317,13 +1319,10 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
Ok(FrameControl::Continue)
|
||||
}
|
||||
|
||||
fn op_convert_d(
|
||||
&mut self,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
) -> Result<FrameControl<'gc>, Error> {
|
||||
let value = self.avm2.pop().coerce_to_number(self, context)?;
|
||||
fn op_convert_d(&mut self) -> Result<FrameControl<'gc>, Error> {
|
||||
let value = self.context.avm2.pop().coerce_to_number(self)?;
|
||||
|
||||
self.avm2.push(Value::Number(value));
|
||||
self.context.avm2.push(Value::Number(value));
|
||||
|
||||
Ok(FrameControl::Continue)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ use crate::avm2::object::{Object, TObject};
|
|||
use crate::avm2::script::TranslationUnit;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::Error;
|
||||
use crate::context::UpdateContext;
|
||||
use gc_arena::{Collect, MutationContext};
|
||||
use std::f64::NAN;
|
||||
use swf::avm2::types::{DefaultValue as AbcDefaultValue, Index};
|
||||
|
@ -293,21 +292,17 @@ impl<'gc> Value<'gc> {
|
|||
pub fn coerce_to_primitive(
|
||||
&self,
|
||||
hint: Hint,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
match self {
|
||||
Value::Object(o) if hint == Hint::String => {
|
||||
let mut prim = self.clone();
|
||||
let mut object = *o;
|
||||
|
||||
if let Value::Object(f) = object.get_property(
|
||||
*o,
|
||||
&QName::dynamic_name("toString"),
|
||||
activation,
|
||||
context,
|
||||
)? {
|
||||
prim = f.call(Some(*o), &[], activation, context, None)?;
|
||||
if let Value::Object(f) =
|
||||
object.get_property(*o, &QName::dynamic_name("toString"), activation)?
|
||||
{
|
||||
prim = f.call(Some(*o), &[], activation, None)?;
|
||||
}
|
||||
|
||||
if prim.is_primitive() {
|
||||
|
@ -315,9 +310,9 @@ impl<'gc> Value<'gc> {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -331,22 +326,19 @@ impl<'gc> Value<'gc> {
|
|||
let mut object = *o;
|
||||
|
||||
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() {
|
||||
return Ok(prim);
|
||||
}
|
||||
|
||||
if let Value::Object(f) = object.get_property(
|
||||
*o,
|
||||
&QName::dynamic_name("toString"),
|
||||
activation,
|
||||
context,
|
||||
)? {
|
||||
prim = f.call(Some(*o), &[], activation, context, None)?;
|
||||
if let Value::Object(f) =
|
||||
object.get_property(*o, &QName::dynamic_name("toString"), activation)?
|
||||
{
|
||||
prim = f.call(Some(*o), &[], activation, None)?;
|
||||
}
|
||||
|
||||
if prim.is_primitive() {
|
||||
|
@ -367,11 +359,7 @@ impl<'gc> Value<'gc> {
|
|||
///
|
||||
/// Numerical conversions occur according to ECMA-262 3rd Edition's
|
||||
/// ToNumber algorithm which appears to match AVM2.
|
||||
pub fn coerce_to_number(
|
||||
&self,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
) -> Result<f64, Error> {
|
||||
pub fn coerce_to_number(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<f64, Error> {
|
||||
Ok(match self {
|
||||
Value::Undefined => f64::NAN,
|
||||
Value::Null => 0.0,
|
||||
|
@ -427,13 +415,14 @@ impl<'gc> Value<'gc> {
|
|||
sign * digits.parse().unwrap_or(f64::NAN)
|
||||
}
|
||||
}
|
||||
Value::Namespace(ns) => {
|
||||
Value::String(AvmString::new(context.gc_context, ns.as_uri().to_string()))
|
||||
.coerce_to_number(activation, context)?
|
||||
}
|
||||
Value::Namespace(ns) => Value::String(AvmString::new(
|
||||
activation.context.gc_context,
|
||||
ns.as_uri().to_string(),
|
||||
))
|
||||
.coerce_to_number(activation)?,
|
||||
Value::Object(_) => self
|
||||
.coerce_to_primitive(Hint::Number, activation, context)?
|
||||
.coerce_to_number(activation, context)?,
|
||||
.coerce_to_primitive(Hint::Number, activation)?
|
||||
.coerce_to_number(activation)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue