@@ -54,82 +54,6 @@ pub fn is_nan<'gc>(
5454 }
5555}
5656
57- /// Converts a `WStr` to an integer (as an `f64`).
58- ///
59- /// This function might fail for some invalid inputs, by returning `f64::NAN`.
60- ///
61- /// `radix` is only valid in the range `2..=36`, plus the special `0` value, which means the
62- /// radix is inferred from the string; hexadecimal if it starts with a `0x` prefix (case
63- /// insensitive), or decimal otherwise.
64- /// `strict` tells whether to fail on trailing garbage, or ignore it.
65- fn string_to_int ( mut s : & WStr , mut radix : i32 , strict : bool ) -> f64 {
66- // Allow leading whitespace.
67- skip_spaces ( & mut s) ;
68-
69- let is_negative = parse_sign ( & mut s) ;
70-
71- if radix == 16 || radix == 0 {
72- if let Some ( after_0x) = s
73- . strip_prefix ( WStr :: from_units ( b"0x" ) )
74- . or_else ( || s. strip_prefix ( WStr :: from_units ( b"0X" ) ) )
75- {
76- // Consume hexadecimal prefix.
77- s = after_0x;
78-
79- // Explicit hexadecimal.
80- radix = 16 ;
81- } else if radix == 0 {
82- // Default to decimal.
83- radix = 10 ;
84- }
85- }
86-
87- // Fail on invalid radix or blank string.
88- if !( 2 ..=36 ) . contains ( & radix) || s. is_empty ( ) {
89- return f64:: NAN ;
90- }
91-
92- // Actual number parsing.
93- let mut result = 0.0 ;
94- let start = s;
95- s = s. trim_start_matches ( |c| {
96- match u8:: try_from ( c)
97- . ok ( )
98- . and_then ( |c| char:: from ( c) . to_digit ( radix as u32 ) )
99- {
100- Some ( digit) => {
101- result *= f64:: from ( radix) ;
102- result += f64:: from ( digit) ;
103- true
104- }
105- None => false ,
106- }
107- } ) ;
108-
109- // Fail if we got no digits.
110- // TODO: Compare by reference instead?
111- if s. len ( ) == start. len ( ) {
112- return f64:: NAN ;
113- }
114-
115- if strict {
116- // Allow trailing whitespace.
117- skip_spaces ( & mut s) ;
118-
119- // Fail if we got digits, but we're in strict mode and not at end of string.
120- if !s. is_empty ( ) {
121- return f64:: NAN ;
122- }
123- }
124-
125- // Apply sign.
126- if is_negative {
127- result = -result;
128- }
129-
130- result
131- }
132-
13357pub fn parse_int < ' gc > (
13458 activation : & mut Activation < ' _ , ' gc , ' _ > ,
13559 _this : Option < Object < ' gc > > ,
@@ -145,224 +69,10 @@ pub fn parse_int<'gc>(
14569 None => 0 ,
14670 } ;
14771
148- let result = string_to_int ( & string, radix, false ) ;
72+ let result = crate :: avm2 :: value :: string_to_int ( & string, radix, false ) ;
14973 Ok ( result. into ( ) )
15074}
15175
152- /// Strips leading whitespace.
153- fn skip_spaces ( s : & mut & WStr ) {
154- * s = s. trim_start_matches ( |c| {
155- matches ! (
156- c,
157- 0x20 | 0x09 | 0x0d | 0x0a | 0x0c | 0x0b | 0x2000
158- ..=0x200b | 0x2028 | 0x2029 | 0x205f | 0x3000
159- )
160- } ) ;
161- }
162-
163- /// Consumes an optional sign character.
164- /// Returns whether a minus sign was consumed.
165- fn parse_sign ( s : & mut & WStr ) -> bool {
166- if let Some ( after_sign) = s. strip_prefix ( b'-' ) {
167- * s = after_sign;
168- true
169- } else if let Some ( after_sign) = s. strip_prefix ( b'+' ) {
170- * s = after_sign;
171- false
172- } else {
173- false
174- }
175- }
176-
177- /// Converts a `WStr` to an `f64`.
178- ///
179- /// This function might fail for some invalid inputs, by returning `None`.
180- ///
181- /// `strict` typically tells whether to behave like `Number()` or `parseFloat()`:
182- /// * `strict == true` fails on trailing garbage, but interprets blank strings (which are empty or consist only of whitespace) as zero.
183- /// * `strict == false` ignores trailing garbage, but fails on blank strings.
184- fn string_to_f64 ( mut s : & WStr , swf_version : u8 , strict : bool ) -> Option < f64 > {
185- fn is_ascii_digit ( c : u16 ) -> bool {
186- u8:: try_from ( c) . map_or ( false , |c| c. is_ascii_digit ( ) )
187- }
188-
189- // Allow leading whitespace.
190- skip_spaces ( & mut s) ;
191-
192- // Handle blank strings as described above.
193- if s. is_empty ( ) {
194- return if strict { Some ( 0.0 ) } else { None } ;
195- }
196-
197- // Parse sign.
198- let is_negative = parse_sign ( & mut s) ;
199- let after_sign = s;
200-
201- // Count digits before decimal point.
202- s = s. trim_start_matches ( is_ascii_digit) ;
203- let mut total_digits = after_sign. len ( ) - s. len ( ) ;
204-
205- // Count digits after decimal point.
206- if let Some ( after_dot) = s. strip_prefix ( b'.' ) {
207- s = after_dot;
208- s = s. trim_start_matches ( is_ascii_digit) ;
209- total_digits += after_dot. len ( ) - s. len ( ) ;
210- }
211-
212- // Handle exponent.
213- let mut exponent: i32 = 0 ;
214- if let Some ( after_e) = s. strip_prefix ( b"eE" . as_ref ( ) ) {
215- s = after_e;
216-
217- // Parse exponent sign.
218- let exponent_is_negative = parse_sign ( & mut s) ;
219-
220- // Fail if string ends with "e-" with no exponent value specified.
221- if exponent_is_negative && s. is_empty ( ) {
222- return None ;
223- }
224-
225- // Parse exponent itself.
226- s = s. trim_start_matches ( |c| {
227- match u8:: try_from ( c)
228- . ok ( )
229- . and_then ( |c| char:: from ( c) . to_digit ( 10 ) )
230- {
231- Some ( digit) => {
232- exponent = exponent. wrapping_mul ( 10 ) ;
233- exponent = exponent. wrapping_add ( digit as i32 ) ;
234- true
235- }
236- None => false ,
237- }
238- } ) ;
239-
240- // Apply exponent sign.
241- if exponent_is_negative {
242- exponent = exponent. wrapping_neg ( ) ;
243- }
244- }
245-
246- // Allow trailing whitespace.
247- skip_spaces ( & mut s) ;
248-
249- // If we got no digits, check for Infinity/-Infinity. Otherwise fail.
250- if total_digits == 0 {
251- if let Some ( after_infinity) = s. strip_prefix ( WStr :: from_units ( b"Infinity" ) ) {
252- s = after_infinity;
253-
254- // Allow end of string or a whitespace. Otherwise fail.
255- if !s. is_empty ( ) {
256- skip_spaces ( & mut s) ;
257- // TODO: Compare by reference instead?
258- if s. len ( ) == after_infinity. len ( ) {
259- return None ;
260- }
261- }
262-
263- let result = if is_negative {
264- f64:: NEG_INFINITY
265- } else {
266- f64:: INFINITY
267- } ;
268- return Some ( result) ;
269- }
270- return None ;
271- }
272-
273- // Fail if we got digits, but we're in strict mode and not at end of string or at a null character.
274- if strict && !s. is_empty ( ) && !s. starts_with ( b'\0' ) {
275- return None ;
276- }
277-
278- // Bug compatibility: https://bugzilla.mozilla.org/show_bug.cgi?id=513018
279- let s = if swf_version >= 11 {
280- & after_sign[ ..after_sign. len ( ) - s. len ( ) ]
281- } else {
282- after_sign
283- } ;
284-
285- // Finally, calculate the result.
286- let mut result = if total_digits > 15 {
287- // With more than 15 digits, avmplus uses integer arithmetic to avoid rounding errors.
288- let mut result: i64 = 0 ;
289- let mut decimal_digits = -1 ;
290- for c in s {
291- if let Some ( digit) = u8:: try_from ( c)
292- . ok ( )
293- . and_then ( |c| char:: from ( c) . to_digit ( 10 ) )
294- {
295- if decimal_digits != -1 {
296- decimal_digits += 1 ;
297- }
298-
299- result *= 10 ;
300- result += i64:: from ( digit) ;
301- } else if c == b'.' as u16 {
302- decimal_digits = 0 ;
303- } else {
304- break ;
305- }
306- }
307-
308- if decimal_digits > 0 {
309- exponent -= decimal_digits;
310- }
311-
312- if exponent > 0 {
313- result *= i64:: pow ( 10 , exponent as u32 ) ;
314- }
315-
316- result as f64
317- } else {
318- let mut result = 0.0 ;
319- let mut decimal_digits = -1 ;
320- for c in s {
321- if let Some ( digit) = u8:: try_from ( c)
322- . ok ( )
323- . and_then ( |c| char:: from ( c) . to_digit ( 10 ) )
324- {
325- if decimal_digits != -1 {
326- decimal_digits += 1 ;
327- }
328-
329- result *= 10.0 ;
330- result += digit as f64 ;
331- } else if c == b'.' as u16 {
332- decimal_digits = 0 ;
333- } else {
334- break ;
335- }
336- }
337-
338- if decimal_digits > 0 {
339- exponent -= decimal_digits;
340- }
341-
342- if exponent > 0 {
343- result *= f64:: powi ( 10.0 , exponent) ;
344- }
345-
346- result
347- } ;
348-
349- if exponent < 0 {
350- if exponent < -307 {
351- let diff = exponent + 307 ;
352- result /= f64:: powi ( 10.0 , -diff) ;
353- exponent = -307 ;
354- }
355- result /= f64:: powi ( 10.0 , -exponent) ;
356- }
357-
358- // Apply sign.
359- if is_negative {
360- result = -result;
361- }
362-
363- Some ( result)
364- }
365-
36676pub fn parse_float < ' gc > (
36777 activation : & mut Activation < ' _ , ' gc , ' _ > ,
36878 _this : Option < Object < ' gc > > ,
@@ -371,7 +81,7 @@ pub fn parse_float<'gc>(
37181 if let Some ( value) = args. get ( 0 ) {
37282 let string = value. coerce_to_string ( activation) ?;
37383 let swf_version = activation. context . swf . version ( ) ;
374- if let Some ( result) = string_to_f64 ( & string, swf_version, false ) {
84+ if let Some ( result) = crate :: avm2 :: value :: string_to_f64 ( & string, swf_version, false ) {
37585 return Ok ( result. into ( ) ) ;
37686 }
37787 }
0 commit comments