avm1: Correct `Value::as_bool(String)` in SWFv6 and below
This commit is contained in:
parent
811af340c3
commit
61fa38e70f
|
@ -129,7 +129,7 @@ impl<'gc> Value<'gc> {
|
||||||
!matches!(self, Value::Object(_))
|
!matches!(self, Value::Object(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ECMA-262 2nd edtion s. 9.3 ToNumber (after calling `to_primitive_num`)
|
/// ECMA-262 2nd edition s. 9.3 ToNumber (after calling `to_primitive_num`)
|
||||||
///
|
///
|
||||||
/// Flash diverges from spec in a number of ways. These ways are, as far as
|
/// Flash diverges from spec in a number of ways. These ways are, as far as
|
||||||
/// we are aware, version-gated:
|
/// we are aware, version-gated:
|
||||||
|
@ -137,62 +137,20 @@ impl<'gc> Value<'gc> {
|
||||||
/// * In SWF6 and lower, `undefined` is coerced to `0.0` (like `false`)
|
/// * In SWF6 and lower, `undefined` is coerced to `0.0` (like `false`)
|
||||||
/// rather than `NaN` as required by spec.
|
/// rather than `NaN` as required by spec.
|
||||||
/// * In SWF5 and lower, hexadecimal is unsupported.
|
/// * In SWF5 and lower, hexadecimal is unsupported.
|
||||||
|
/// * In SWF4 and lower, a string is coerced using the `parseFloat` function
|
||||||
|
/// and returns `0.0` rather than `NaN` if it cannot be converted to a number.
|
||||||
fn primitive_as_number(&self, activation: &mut Activation<'_, 'gc, '_>) -> f64 {
|
fn primitive_as_number(&self, activation: &mut Activation<'_, 'gc, '_>) -> f64 {
|
||||||
let v = match self {
|
match self {
|
||||||
Value::Undefined if activation.swf_version() < 7 => return 0.0,
|
Value::Undefined if activation.swf_version() < 7 => 0.0,
|
||||||
Value::Null if activation.swf_version() < 7 => return 0.0,
|
Value::Null if activation.swf_version() < 7 => 0.0,
|
||||||
Value::Object(_) if activation.swf_version() < 5 => return 0.0,
|
Value::Object(_) if activation.swf_version() < 5 => 0.0,
|
||||||
Value::String(v) if activation.swf_version() < 5 => {
|
Value::Undefined => f64::NAN,
|
||||||
use crate::avm1::globals::parse_float_impl;
|
Value::Null => f64::NAN,
|
||||||
let result = parse_float_impl(v.trim_start(), true);
|
Value::Bool(false) => 0.0,
|
||||||
if result.is_nan() {
|
Value::Bool(true) => 1.0,
|
||||||
return 0.0;
|
Value::Number(v) => *v,
|
||||||
}
|
Value::Object(_) => f64::NAN,
|
||||||
return result;
|
Value::String(v) => string_to_f64(&v, activation.swf_version()),
|
||||||
}
|
|
||||||
Value::Undefined => return f64::NAN,
|
|
||||||
Value::Null => return f64::NAN,
|
|
||||||
Value::Bool(false) => return 0.0,
|
|
||||||
Value::Bool(true) => return 1.0,
|
|
||||||
Value::Number(v) => return *v,
|
|
||||||
Value::Object(_) => return f64::NAN,
|
|
||||||
Value::String(v) => v,
|
|
||||||
};
|
|
||||||
|
|
||||||
if v.is_empty() {
|
|
||||||
return f64::NAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if activation.swf_version() >= 6 {
|
|
||||||
if let Some(v) = v.strip_prefix(WStr::from_units(b"0x")) {
|
|
||||||
// Flash allows the '-' sign here.
|
|
||||||
return match Wrapping::<i32>::from_wstr_radix(v, 16) {
|
|
||||||
Ok(n) => f64::from(n.0 as i32),
|
|
||||||
Err(_) => f64::NAN,
|
|
||||||
};
|
|
||||||
} else if v.starts_with(b'0')
|
|
||||||
|| v.starts_with(WStr::from_units(b"+0"))
|
|
||||||
|| v.starts_with(WStr::from_units(b"-0"))
|
|
||||||
{
|
|
||||||
// Flash allows the '-' sign here.
|
|
||||||
if let Ok(n) = Wrapping::<i32>::from_wstr_radix(v, 8) {
|
|
||||||
return f64::from(n.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rust parses "inf" and "+inf" into Infinity, but Flash doesn't.
|
|
||||||
// (as of nightly 4/13, Rust also accepts "infinity")
|
|
||||||
// Check if the string starts with 'i' (ignoring any leading +/-).
|
|
||||||
if v.strip_prefix(&b"+-"[..])
|
|
||||||
.unwrap_or(v)
|
|
||||||
.starts_with(&b"iI"[..])
|
|
||||||
{
|
|
||||||
f64::NAN
|
|
||||||
} else {
|
|
||||||
v.trim_start_matches(&b"\t\n\r "[..])
|
|
||||||
.parse()
|
|
||||||
.unwrap_or(f64::NAN)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,8 +424,8 @@ impl<'gc> Value<'gc> {
|
||||||
if swf_version >= 7 {
|
if swf_version >= 7 {
|
||||||
!v.is_empty()
|
!v.is_empty()
|
||||||
} else {
|
} else {
|
||||||
let num = v.parse().unwrap_or(0.0);
|
let num = string_to_f64(&v, swf_version);
|
||||||
num != 0.0
|
!num.is_nan() && num != 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Object(_) => true,
|
Value::Object(_) => true,
|
||||||
|
@ -713,6 +671,54 @@ fn f64_to_string(mut n: f64) -> Cow<'static, str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a `WStr` to an f64 based on the SWF version.
|
||||||
|
fn string_to_f64(str: &WStr, swf_version: u8) -> f64 {
|
||||||
|
if swf_version < 5 {
|
||||||
|
use crate::avm1::globals::parse_float_impl;
|
||||||
|
let v = parse_float_impl(str.trim_start(), true);
|
||||||
|
if v.is_nan() {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if str.is_empty() {
|
||||||
|
return f64::NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if swf_version >= 6 {
|
||||||
|
if let Some(v) = str.strip_prefix(WStr::from_units(b"0x")) {
|
||||||
|
// Flash allows the '-' sign here.
|
||||||
|
return match Wrapping::<i32>::from_wstr_radix(v, 16) {
|
||||||
|
Ok(n) => f64::from(n.0 as i32),
|
||||||
|
Err(_) => f64::NAN,
|
||||||
|
};
|
||||||
|
} else if str.starts_with(b'0')
|
||||||
|
|| str.starts_with(WStr::from_units(b"+0"))
|
||||||
|
|| str.starts_with(WStr::from_units(b"-0"))
|
||||||
|
{
|
||||||
|
// Flash allows the '-' sign here.
|
||||||
|
if let Ok(n) = Wrapping::<i32>::from_wstr_radix(str, 8) {
|
||||||
|
return f64::from(n.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rust parses "inf", "+inf" and "infinity" into Infinity, but Flash doesn't.
|
||||||
|
// Check if the string starts with 'i' (ignoring any leading +/-).
|
||||||
|
if str
|
||||||
|
.strip_prefix(&b"+-"[..])
|
||||||
|
.unwrap_or(str)
|
||||||
|
.starts_with(&b"iI"[..])
|
||||||
|
{
|
||||||
|
f64::NAN
|
||||||
|
} else {
|
||||||
|
str.trim_start_matches(&b"\t\n\r "[..])
|
||||||
|
.parse()
|
||||||
|
.unwrap_or(f64::NAN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::unreadable_literal)] // Large numeric literals in tests
|
#[allow(clippy::unreadable_literal)] // Large numeric literals in tests
|
||||||
mod test {
|
mod test {
|
||||||
|
|
Loading…
Reference in New Issue