Skip to content

Commit b7dddd1

Browse files
committed
Make parseInt unicode tolerant.
JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
1 parent ee8d650 commit b7dddd1

File tree

2 files changed

+72
-29
lines changed

2 files changed

+72
-29
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-global.cpp

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -121,17 +121,25 @@ ecma_builtin_global_object_parse_int (ecma_value_t this_arg __attr_unused___, /*
121121
utf8_string_buff,
122122
(ssize_t) str_size);
123123
JERRY_ASSERT (bytes_copied >= 0);
124-
utf8_string_buff[str_size] = LIT_BYTE_NULL;
124+
lit_utf8_iterator_t iter = lit_utf8_iterator_create (utf8_string_buff, str_size);
125125

126126
/* 2. Remove leading whitespace. */
127-
ecma_length_t start = str_size;
128-
ecma_length_t end = str_size;
129-
for (ecma_length_t i = 0; i < end; i++)
127+
lit_utf8_iterator_seek_eos (&iter);
128+
129+
lit_utf8_iterator_pos_t start = lit_utf8_iterator_get_pos (&iter);
130+
lit_utf8_iterator_pos_t end = lit_utf8_iterator_get_pos (&iter);
131+
132+
lit_utf8_iterator_seek_bos (&iter);
133+
134+
while (!lit_utf8_iterator_is_eos (&iter))
130135
{
131-
if (!lit_char_is_white_space (utf8_string_buff[i])
132-
&& !lit_char_is_line_terminator (utf8_string_buff[i]))
136+
ecma_char_t current_char = lit_utf8_iterator_read_next (&iter);
137+
138+
if (!lit_char_is_white_space (current_char)
139+
&& !lit_char_is_line_terminator (current_char))
133140
{
134-
start = i;
141+
lit_utf8_iterator_read_prev (&iter);
142+
start = lit_utf8_iterator_get_pos (&iter);
135143
break;
136144
}
137145
}
@@ -140,15 +148,17 @@ ecma_builtin_global_object_parse_int (ecma_value_t this_arg __attr_unused___, /*
140148
int sign = 1;
141149

142150
/* 4. */
143-
if (utf8_string_buff[start] == LIT_CHAR_MINUS)
151+
ecma_char_t current = lit_utf8_iterator_read_next (&iter);
152+
if (current == LIT_CHAR_MINUS)
144153
{
145154
sign = -1;
146155
}
147156

148157
/* 5. */
149-
if (utf8_string_buff[start] == LIT_CHAR_MINUS || utf8_string_buff[start] == LIT_CHAR_PLUS)
158+
if (current == LIT_CHAR_MINUS || current == LIT_CHAR_PLUS)
150159
{
151-
start++;
160+
start = lit_utf8_iterator_get_pos (&iter);
161+
current = lit_utf8_iterator_read_next (&iter);
152162
}
153163

154164
/* 6. */
@@ -185,47 +195,55 @@ ecma_builtin_global_object_parse_int (ecma_value_t this_arg __attr_unused___, /*
185195
/* 10. */
186196
if (strip_prefix)
187197
{
188-
if (end - start >= 2
189-
&& utf8_string_buff[start] == LIT_CHAR_0
190-
&& (utf8_string_buff[start + 1] == LIT_CHAR_LOWERCASE_X
191-
|| utf8_string_buff[start + 1] == LIT_CHAR_UPPERCASE_X))
198+
if (end.offset - start.offset >= 2 && current == LIT_CHAR_0)
192199
{
193-
start += 2;
200+
ecma_char_t next = lit_utf8_iterator_peek_next (&iter);
201+
if (next == LIT_CHAR_LOWERCASE_X || next == LIT_CHAR_UPPERCASE_X)
202+
{
203+
/* Skip the 'x' or 'X' characters. */
204+
lit_utf8_iterator_incr (&iter);
205+
start = lit_utf8_iterator_get_pos (&iter);
194206

195-
rad = 16;
207+
rad = 16;
208+
}
196209
}
197210
}
198211

199212
/* 11. Check if characters are in [0, Radix - 1]. We also convert them to number values in the process. */
200-
for (lit_utf8_size_t i = start; i < end; i++)
213+
lit_utf8_iterator_seek (&iter, start);
214+
while (!lit_utf8_iterator_is_eos (&iter))
201215
{
202-
if ((utf8_string_buff[i]) >= LIT_CHAR_LOWERCASE_A && utf8_string_buff[i] <= LIT_CHAR_LOWERCASE_Z)
216+
ecma_char_t current_char = lit_utf8_iterator_read_next (&iter);
217+
ecma_number_t current_number;
218+
219+
if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z))
203220
{
204-
utf8_string_buff[i] = (lit_utf8_byte_t) (utf8_string_buff[i] - LIT_CHAR_LOWERCASE_A + 10);
221+
current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10;
205222
}
206-
else if (utf8_string_buff[i] >= LIT_CHAR_UPPERCASE_A && utf8_string_buff[i] <= LIT_CHAR_UPPERCASE_Z)
223+
else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z))
207224
{
208-
utf8_string_buff[i] = (lit_utf8_byte_t) (utf8_string_buff[i] - LIT_CHAR_UPPERCASE_A + 10);
225+
current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10;
209226
}
210-
else if (lit_char_is_decimal_digit (utf8_string_buff[i]))
227+
else if (lit_char_is_decimal_digit (current_char))
211228
{
212-
utf8_string_buff[i] = (lit_utf8_byte_t) (utf8_string_buff[i] - LIT_CHAR_0);
229+
current_number = (ecma_number_t) current_char - LIT_CHAR_0;
213230
}
214231
else
215232
{
216233
/* Not a valid number char, set value to radix so it fails to pass as a valid character. */
217-
utf8_string_buff[i] = (lit_utf8_byte_t) rad;
234+
current_number = (ecma_number_t) rad;
218235
}
219236

220-
if (!(utf8_string_buff[i] < rad))
237+
if (!(current_number < rad))
221238
{
222-
end = i;
239+
lit_utf8_iterator_decr (&iter);
240+
end = lit_utf8_iterator_get_pos (&iter);
223241
break;
224242
}
225243
}
226244

227245
/* 12. */
228-
if (end - start == 0)
246+
if (end.offset - start.offset == 0)
229247
{
230248
ecma_number_t *ret_num_p = ecma_alloc_number ();
231249
*ret_num_p = ecma_number_make_nan ();
@@ -240,9 +258,30 @@ ecma_builtin_global_object_parse_int (ecma_value_t this_arg __attr_unused___, /*
240258
ecma_number_t multiplier = 1.0f;
241259

242260
/* 13. and 14. */
243-
for (int32_t i = (int32_t) end - 1; i >= (int32_t) start; i--)
261+
lit_utf8_iterator_seek (&iter, end);
262+
while (lit_utf8_iterator_get_pos (&iter).offset > start.offset)
244263
{
245-
*value_p += (ecma_number_t) utf8_string_buff[i] * multiplier;
264+
ecma_char_t current_char = lit_utf8_iterator_read_prev (&iter);
265+
ecma_number_t current_number;
266+
267+
if ((current_char >= LIT_CHAR_LOWERCASE_A && current_char <= LIT_CHAR_LOWERCASE_Z))
268+
{
269+
current_number = (ecma_number_t) current_char - LIT_CHAR_LOWERCASE_A + 10;
270+
}
271+
else if ((current_char >= LIT_CHAR_UPPERCASE_A && current_char <= LIT_CHAR_UPPERCASE_Z))
272+
{
273+
current_number = (ecma_number_t) current_char - LIT_CHAR_UPPERCASE_A + 10;
274+
}
275+
else if (lit_char_is_decimal_digit (current_char))
276+
{
277+
current_number = (ecma_number_t) current_char - LIT_CHAR_0;
278+
}
279+
else
280+
{
281+
JERRY_UNREACHABLE ();
282+
}
283+
284+
*value_p += current_number * multiplier;
246285
multiplier *= (ecma_number_t) rad;
247286
}
248287

tests/jerry/global-parseint.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ assert(parseInt("12A3") === 12);
2828
assert(parseInt("12.34") === 12);
2929
assert(isNaN(parseInt("AB")));
3030
assert(isNaN(parseInt("")));
31+
assert(parseInt("\u00a0123") === 123);
32+
assert(parseInt("\u20291 123\u00D0") === 1);
33+
assert(parseInt("\u00a0123", 13) === 198);
34+
assert(parseInt("\u2029123 1\u00D0", 11) === 146);
3135

3236
var bool = true;
3337
var obj = new Object();

0 commit comments

Comments
 (0)