avm1: parseInt

This commit is contained in:
Albert Safin 2020-08-08 22:01:51 +00:00 committed by Mike Welsh
parent cbd448522a
commit e03373bceb
5 changed files with 288 additions and 0 deletions

View File

@ -81,6 +81,109 @@ pub fn is_nan<'gc>(
}
}
pub fn parse_int<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
// ECMA-262 violation: parseInt() == undefined // not NaN
if args.is_empty() {
return Ok(Value::Undefined);
}
let radix: Option<i32> = args
.get(1)
.map(|x| x.coerce_to_i32(activation))
.transpose()?;
if let Some(radix) = radix {
if radix < 2 || radix > 36 {
return Ok(f64::NAN.into());
}
}
let string = args
.get(0)
.unwrap_or(&Value::Undefined)
.coerce_to_string(activation)?;
let mut string_s = string.as_bytes();
let mut ignore_sign = false;
let radix = match string_s {
// Emulate bug: unless "0x" is a valid sequence of digits in a given radix, these prefixes
// should result in NaN instead of 0. Otherwise, the minus sign should be ignored.
[b'+', b'0', b'x', ..]
| [b'+', b'0', b'X', ..]
| [b'-', b'0', b'x', ..]
| [b'-', b'0', b'X', ..] => {
if radix.unwrap_or(0) <= 33 {
return Ok(f64::NAN.into());
} else {
ignore_sign = true;
radix.unwrap() // radix is present and is > 33
}
}
// Auto-detect hexadecimal prefix and strip it.
// Emulate bug: the prefix is stripped irregardless of the radix.
// parseInt('0x100', 10) == 100 // not 0
// parseInt('0x100', 36) == 1296 // not 1540944
// Emulate bug: the prefix is expected before the sign or spaces.
// parseInt("0x -10") == -16 // not NaN
// parseInt(" -0x10") == NaN // not -16
[b'0', b'x', rest @ ..] | [b'0', b'X', rest @ ..] => {
string_s = rest;
radix.unwrap_or(16)
}
// ECMA-262 violation: auto-detect octal numbers.
// An auto-detected octal number cannot contain leading spaces or extra trailing characters.
[b'0', rest @ ..] | [b'+', b'0', rest @ ..] | [b'-', b'0', rest @ ..]
if radix.is_none() && rest.iter().all(|&x| b'0' <= x && x <= b'7') =>
{
8
}
_ => radix.unwrap_or(10),
};
// Strip spaces.
while let Some(chr) = string_s.first() {
if !b"\t\n\r ".contains(chr) {
break;
}
string_s = &string_s[1..];
}
let (sign, string_s) = match string_s {
[b'+', rest @ ..] => (1., rest),
[b'-', rest @ ..] => (-1., rest),
rest => (1., rest),
};
let sign = if ignore_sign { 1. } else { sign };
let mut empty = true;
let mut result = 0.0f64;
for &chr in string_s {
let digit = match chr {
b'0'..=b'9' => chr as u32 - b'0' as u32,
b'a'..=b'z' => chr as u32 - b'a' as u32 + 10,
b'A'..=b'Z' => chr as u32 - b'A' as u32 + 10,
_ => break,
};
if digit as i32 >= radix {
break;
}
result = result * radix as f64 + digit as f64;
empty = false;
}
if empty {
Ok(f64::NAN.into())
} else {
Ok(result.copysign(sign).into())
}
}
pub fn get_infinity<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_this: Object<'gc>,
@ -550,6 +653,13 @@ pub fn create_globals<'gc>(
Some(function_proto),
);
globals.force_set_function("isNaN", is_nan, gc_context, DontEnum, Some(function_proto));
globals.force_set_function(
"parseInt",
parse_int,
gc_context,
DontEnum,
Some(function_proto),
);
globals.force_set_function("random", random, gc_context, DontEnum, Some(function_proto));
globals.force_set_function(
"ASSetPropFlags",

View File

@ -239,6 +239,7 @@ swf_tests! {
(array_constructor, "avm1/array_constructor", 1),
(array_apply, "avm1/array_constructor", 1),
(object_function, "avm1/object_function", 1),
(parse_int, "avm1/parse_int", 1),
(as3_hello_world, "avm2/hello_world", 1),
(as3_function_call, "avm2/function_call", 1),
(as3_function_call_via_call, "avm2/function_call_via_call", 1),

View File

@ -0,0 +1,64 @@
/*0*/ parseInt() == undefined
/*1*/ parseInt('undefined') == NaN
/*2*/ parseInt('undefined', 32) == 33790067563981
/*3*/ parseInt('') == NaN
/*4*/ parseInt('123') == 123
/*5*/ parseInt('100', 10) == 100
/*6*/ parseInt('100', 0) == NaN
/*7*/ parseInt('100', 1) == NaN
/*8*/ parseInt('100', 2) == 4
/*9*/ parseInt('100', 36) == 1296
/*10*/ parseInt('100', 37) == NaN
/*11*/ parseInt('100', -1) == NaN
/*12*/ parseInt('100', [object Object]) == NaN
/*13*/ parseInt('100', true) == NaN
/*14*/ parseInt('100', false) == NaN
/*15*/ parseInt('100', NaN) == NaN
/*16*/ parseInt('100', undefined) == NaN
/*17*/ parseInt('0x123') == 291
/*18*/ parseInt('0xabc') == 2748
/*19*/ parseInt('010', 2) == 2
/*20*/ parseInt('-0100') == -64
/*21*/ parseInt('-0100z') == -100
/*22*/ parseInt('0x+0X100') == 0
/*23*/ parseInt('123') == 123
/*24*/ parseInt('123', 32) == 1091
/*25*/ parseInt('++1') == NaN
/*26*/ parseInt('0x100', 36) == 1296
/*27*/ parseInt(' 0x100', 36) == 1540944
/*28*/ parseInt('0y100', 36) == 1587600
/*29*/ parseInt(' 0y100', 36) == 1587600
/*30*/ parseInt('-0x100', 36) == 1540944
/*31*/ parseInt(' -0x100', 36) == -1540944
/*32*/ parseInt('-0y100', 36) == -1587600
/*33*/ parseInt(' -0y100', 36) == -1587600
/*34*/ parseInt('-0x100') == NaN
/*35*/ parseInt('0x-100') == -256
/*36*/ parseInt(' 0x-100') == 0
/*37*/ parseInt('0x -100') == -256
/*38*/ parseInt('-0100') == -64
/*39*/ parseInt('0-100') == 0
/*40*/ parseInt('+0x123', 33) == NaN
/*41*/ parseInt('+0x123', 34) == 1298259
/*42*/ parseInt('0') == 0
/*43*/ parseInt(' 0') == 0
/*44*/ parseInt(' 0 ') == 0
/*45*/ parseInt('077') == 63
/*46*/ parseInt(' 077') == 77
/*47*/ parseInt(' 077 ') == 77
/*48*/ parseInt(' -077') == -77
/*49*/ parseInt('077 ') == 77
/*50*/ parseInt('11', 2) == 3
/*51*/ parseInt('11', 3) == 4
/*52*/ parseInt('11', 3.8) == 4
/*53*/ parseInt('0x12') == 18
/*54*/ parseInt('0x12', 16) == 18
/*55*/ parseInt('0x12', 16.1) == 18
/*56*/ parseInt('0x12', NaN) == NaN
/*57*/ parseInt('0x ') == NaN
/*58*/ parseInt('0x') == NaN
/*59*/ parseInt('0x ', 16) == NaN
/*60*/ parseInt('0x', 16) == NaN
/*61*/ parseInt('12aaa') == 12
/*62*/ parseInt('10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000') == Infinity
/*63*/ parseInt('0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000') == Infinity

View File

@ -0,0 +1,113 @@
.flash bbox=300x200 version=8 name="test.swf" compress
.action:
var counter = 0;
function traceParseInt() {
var args;
var result;
switch (arguments.length) {
case 0:
args = '';
result = parseInt();
break;
case 1:
args = "'" + arguments[0].toString() + "'";
result = parseInt(arguments[0]);
break;
case 2:
args = "'" + arguments[0].toString() + "', " + arguments[1].toString();
result = parseInt(arguments[0], arguments[1]);
break;
}
trace('/*' + counter++ + '*/ parseInt(' + args + ') == ' + result.toString());
}
var undefined_;
traceParseInt();
traceParseInt(undefined_);
traceParseInt(undefined_, 32);
traceParseInt('');
traceParseInt('123');
traceParseInt('100', 10);
traceParseInt('100', 0);
traceParseInt('100', 1);
traceParseInt('100', 2);
traceParseInt('100', 36);
traceParseInt('100', 37);
traceParseInt('100', -1);
traceParseInt('100', {});
traceParseInt('100', true);
traceParseInt('100', false);
traceParseInt('100', NaN);
traceParseInt('100', undefined_);
traceParseInt('0x123');
traceParseInt('0xabc');
traceParseInt('010', 2);
traceParseInt('-0100');
traceParseInt('-0100z');
traceParseInt('0x+0X100');
traceParseInt(123);
traceParseInt(123, 32);
traceParseInt('++1');
traceParseInt('0x100', 36);
traceParseInt(' 0x100', 36);
traceParseInt('0y100', 36);
traceParseInt(' 0y100', 36);
traceParseInt('-0x100', 36);
traceParseInt(' -0x100', 36);
traceParseInt('-0y100', 36);
traceParseInt(' -0y100', 36);
traceParseInt('-0x100');
traceParseInt('0x-100');
traceParseInt(' 0x-100');
traceParseInt('0x -100');
traceParseInt('-0100');
traceParseInt('0-100');
traceParseInt('+0x123', 33);
traceParseInt('+0x123', 34);
traceParseInt('0');
traceParseInt(' 0');
traceParseInt(' 0 ');
traceParseInt('077');
traceParseInt(' 077');
traceParseInt(' 077 ');
traceParseInt(' -077');
traceParseInt('077 ');
traceParseInt('11', 2);
traceParseInt('11', 3);
traceParseInt('11', 3.8);
traceParseInt('0x12');
traceParseInt('0x12', 16);
traceParseInt('0x12', 16.1);
traceParseInt('0x12', NaN);
traceParseInt('0x ');
traceParseInt('0x');
traceParseInt('0x ', 16);
traceParseInt('0x', 16);
traceParseInt('12aaa');
traceParseInt('100000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '000000000000000');
traceParseInt('0x1000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '00000000000000000000000000000000000000000000000000000000000000000000'
+ '000000000000000');
.end
.end

Binary file not shown.