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::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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue