avm1: parseInt
This commit is contained in:
parent
cbd448522a
commit
e03373bceb
|
@ -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",
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
|
@ -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.
Loading…
Reference in New Issue