@@ -63,7 +63,7 @@ pub fn is_nan<'gc>(
6363/// insensitive), or decimal otherwise.
6464/// `strict` tells whether to fail on trailing garbage, or ignore it.
6565fn string_to_int ( mut s : & WStr , mut radix : i32 , strict : bool ) -> f64 {
66- // Allow leading whitespace characters .
66+ // Allow leading whitespace.
6767 skip_spaces ( & mut s) ;
6868
6969 let is_negative = parse_sign ( & mut s) ;
@@ -92,25 +92,31 @@ fn string_to_int(mut s: &WStr, mut radix: i32, strict: bool) -> f64 {
9292 // Actual number parsing.
9393 let mut result = 0.0 ;
9494 let start = s;
95- s = s. trim_start_matches ( |c| match ( c as u8 as char ) . to_digit ( radix as u32 ) {
96- Some ( digit) => {
97- result *= f64:: from ( radix) ;
98- result += f64:: from ( digit) ;
99- true
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 ,
100106 }
101- None => false ,
102107 } ) ;
103108
104109 // Fail if we got no digits.
105- if s == start {
110+ // TODO: Compare by reference instead?
111+ if s. len ( ) == start. len ( ) {
106112 return f64:: NAN ;
107113 }
108114
109115 if strict {
110- // Allow trailing whitespace characters .
116+ // Allow trailing whitespace.
111117 skip_spaces ( & mut s) ;
112118
113- // If we got digits, but we're in strict mode and not at end of string, fail .
119+ // Fail if we got digits, but we're in strict mode and not at end of string.
114120 if !s. is_empty ( ) {
115121 return f64:: NAN ;
116122 }
@@ -143,7 +149,7 @@ pub fn parse_int<'gc>(
143149 Ok ( result. into ( ) )
144150}
145151
146- /// Strips leading whitespace characters .
152+ /// Strips leading whitespace.
147153fn skip_spaces ( s : & mut & WStr ) {
148154 * s = s. trim_start_matches ( |c| {
149155 matches ! (
@@ -173,49 +179,62 @@ fn parse_sign(s: &mut &WStr) -> bool {
173179/// This function might fail for some invalid inputs, by returning `None`.
174180///
175181/// `strict` typically tells whether to behave like `Number()` or `parseFloat()`:
176- /// * `strict == true` fails on trailing garbage, but interprets blank strings (which are empty or consist only of whitespace characters ) as zero.
182+ /// * `strict == true` fails on trailing garbage, but interprets blank strings (which are empty or consist only of whitespace) as zero.
177183/// * `strict == false` ignores trailing garbage, but fails on blank strings.
178184fn string_to_f64 ( mut s : & WStr , swf_version : u8 , strict : bool ) -> Option < f64 > {
179- // Allow leading whitespace characters.
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.
180190 skip_spaces ( & mut s) ;
181191
192+ // Handle blank strings as described above.
182193 if s. is_empty ( ) {
183- // A blank string. Handle it as described above.
184194 return if strict { Some ( 0.0 ) } else { None } ;
185195 }
186196
197+ // Parse sign.
187198 let is_negative = parse_sign ( & mut s) ;
188199 let after_sign = s;
189200
190201 // Count digits before decimal point.
191- s = s. trim_start_matches ( |c| ( c as u8 ) . is_ascii_digit ( ) ) ;
202+ s = s. trim_start_matches ( is_ascii_digit) ;
192203 let mut total_digits = after_sign. len ( ) - s. len ( ) ;
193204
194205 // Count digits after decimal point.
195206 if let Some ( after_dot) = s. strip_prefix ( b'.' ) {
196207 s = after_dot;
197- s = s. trim_start_matches ( |c| ( c as u8 ) . is_ascii_digit ( ) ) ;
208+ s = s. trim_start_matches ( is_ascii_digit) ;
198209 total_digits += after_dot. len ( ) - s. len ( ) ;
199210 }
200211
201212 // Handle exponent.
202213 let mut exponent: i32 = 0 ;
203214 if let Some ( after_e) = s. strip_prefix ( b"eE" . as_ref ( ) ) {
204215 s = after_e;
216+
217+ // Parse exponent sign.
205218 let exponent_is_negative = parse_sign ( & mut s) ;
206219
207220 // Fail if string ends with "e-" with no exponent value specified.
208221 if exponent_is_negative && s. is_empty ( ) {
209222 return None ;
210223 }
211224
212- s = s. trim_start_matches ( |c| match ( c as u8 as char ) . to_digit ( 10 ) {
213- Some ( digit) => {
214- exponent = exponent. wrapping_mul ( 10 ) ;
215- exponent = exponent. wrapping_add ( digit as i32 ) ;
216- true
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 ,
217237 }
218- None => false ,
219238 } ) ;
220239
221240 // Apply exponent sign.
@@ -224,18 +243,19 @@ fn string_to_f64(mut s: &WStr, swf_version: u8, strict: bool) -> Option<f64> {
224243 }
225244 }
226245
227- // Allow trailing whitespace characters .
246+ // Allow trailing whitespace.
228247 skip_spaces ( & mut s) ;
229248
230- // If we got no digits, check for Infinity/-Infinity, else fail.
249+ // If we got no digits, check for Infinity/-Infinity. Otherwise fail.
231250 if total_digits == 0 {
232251 if let Some ( after_infinity) = s. strip_prefix ( WStr :: from_units ( b"Infinity" ) ) {
233252 s = after_infinity;
234253
235- // Allow end of string or a whitespace, and fail otherwise .
254+ // Allow end of string or a whitespace. Otherwise fail.
236255 if !s. is_empty ( ) {
237256 skip_spaces ( & mut s) ;
238- if s == after_infinity {
257+ // TODO: Compare by reference instead?
258+ if s. len ( ) == after_infinity. len ( ) {
239259 return None ;
240260 }
241261 }
@@ -250,7 +270,7 @@ fn string_to_f64(mut s: &WStr, swf_version: u8, strict: bool) -> Option<f64> {
250270 return None ;
251271 }
252272
253- // If we got digits, but we're in strict mode and not at end of string ( or at null character), fail .
273+ // Fail if we got digits, but we're in strict mode and not at end of string or at a null character.
254274 if strict && !s. is_empty ( ) && !s. starts_with ( b'\0' ) {
255275 return None ;
256276 }
@@ -262,12 +282,16 @@ fn string_to_f64(mut s: &WStr, swf_version: u8, strict: bool) -> Option<f64> {
262282 after_sign
263283 } ;
264284
285+ // Finally, calculate the result.
265286 let mut result = if total_digits > 15 {
266287 // With more than 15 digits, avmplus uses integer arithmetic to avoid rounding errors.
267288 let mut result: i64 = 0 ;
268289 let mut decimal_digits = -1 ;
269290 for c in s {
270- if let Some ( digit) = ( c as u8 as char ) . to_digit ( 10 ) {
291+ if let Some ( digit) = u8:: try_from ( c)
292+ . ok ( )
293+ . and_then ( |c| char:: from ( c) . to_digit ( 10 ) )
294+ {
271295 if decimal_digits != -1 {
272296 decimal_digits += 1 ;
273297 }
@@ -294,7 +318,10 @@ fn string_to_f64(mut s: &WStr, swf_version: u8, strict: bool) -> Option<f64> {
294318 let mut result = 0.0 ;
295319 let mut decimal_digits = -1 ;
296320 for c in s {
297- if let Some ( digit) = ( c as u8 as char ) . to_digit ( 10 ) {
321+ if let Some ( digit) = u8:: try_from ( c)
322+ . ok ( )
323+ . and_then ( |c| char:: from ( c) . to_digit ( 10 ) )
324+ {
298325 if decimal_digits != -1 {
299326 decimal_digits += 1 ;
300327 }
0 commit comments