/** * Helper function for finding index of a search string * * This function clamps the given index to the [0, length] range. * If the index is negative, 0 value is used. * If the index is greater than the length of the string, the normalized index will be the length of the string. * NaN is mapped to zero or length depending on the nan_to_zero parameter. * * See also: * ECMA-262 v5, 15.5.4.7,8,11 * * Used by: * - The ecma_builtin_helper_string_prototype_object_index_of helper routine. * - The ecma_builtin_string_prototype_object_replace_match helper routine. * * @return uint32_t - the normalized value of the index */ bool ecma_builtin_helper_string_find_index (ecma_string_t *original_str_p, /**< index */ ecma_string_t *search_str_p, /**< string's length */ bool first_index, /**< whether search for first (t) or last (f) index */ ecma_length_t start_pos, /**< start position */ ecma_length_t *ret_index_p) /**< position found in original string */ { bool match_found = false; const ecma_length_t original_len = ecma_string_get_length (original_str_p); const ecma_length_t search_len = ecma_string_get_length (search_str_p); if (search_len <= original_len) { if (!search_len) { match_found = true; *ret_index_p = first_index ? 0 : original_len; } else { /* create utf8 string from original string and advance to position */ ECMA_STRING_TO_UTF8_STRING (original_str_p, original_str_utf8_p, original_str_size); ecma_length_t index = start_pos; const lit_utf8_byte_t *original_str_curr_p = original_str_utf8_p; for (ecma_length_t idx = 0; idx < index; idx++) { lit_utf8_incr (&original_str_curr_p); } /* create utf8 string from search string */ ECMA_STRING_TO_UTF8_STRING (search_str_p, search_str_utf8_p, search_str_size); const lit_utf8_byte_t *search_str_curr_p = search_str_utf8_p; /* iterate original string and try to match at each position */ bool searching = true; ecma_char_t first_char = lit_utf8_read_next (&search_str_curr_p); while (searching) { /* match as long as possible */ ecma_length_t match_len = 0; const lit_utf8_byte_t *stored_original_str_curr_p = original_str_curr_p; if (match_len < search_len && index + match_len < original_len && lit_utf8_read_next (&original_str_curr_p) == first_char) { const lit_utf8_byte_t *nested_search_str_curr_p = search_str_curr_p; match_len++; while (match_len < search_len && index + match_len < original_len && lit_utf8_read_next (&original_str_curr_p) == lit_utf8_read_next (&nested_search_str_curr_p)) { match_len++; } } /* check for match */ if (match_len == search_len) { match_found = true; *ret_index_p = index; break; } else { /* inc/dec index and update iterators and search condition */ original_str_curr_p = stored_original_str_curr_p; if (first_index) { if ((searching = (index <= original_len - search_len))) { lit_utf8_incr (&original_str_curr_p); index++; } } else { if ((searching = (index > 0))) { lit_utf8_decr (&original_str_curr_p); index--; } } } } ECMA_FINALIZE_UTF8_STRING (search_str_utf8_p, search_str_size); ECMA_FINALIZE_UTF8_STRING (original_str_utf8_p, original_str_size); } } return match_found; } /* ecma_builtin_helper_string_find_index */
int main (int __attr_unused___ argc, char __attr_unused___ **argv) { TEST_INIT (); jmem_init (); lit_init (); ecma_init (); lit_utf8_byte_t cesu8_string[max_bytes_in_string]; ecma_char_t code_units[max_code_units_in_string]; const lit_utf8_byte_t *saved_positions[max_code_units_in_string]; for (int i = 0; i < test_iters; i++) { lit_utf8_size_t cesu8_string_size = (i == 0) ? 0 : (lit_utf8_size_t) (rand () % max_bytes_in_string); ecma_length_t length = generate_cesu8_string (cesu8_string, cesu8_string_size); ecma_string_t *char_collection_string_p = ecma_new_ecma_string_from_utf8 (cesu8_string, cesu8_string_size); ecma_length_t char_collection_len = ecma_string_get_length (char_collection_string_p); JERRY_ASSERT (char_collection_len == length); ecma_deref_ecma_string (char_collection_string_p); JERRY_ASSERT (lit_utf8_string_length (cesu8_string, cesu8_string_size) == length); const lit_utf8_byte_t *curr_p = cesu8_string; const lit_utf8_byte_t *end_p = cesu8_string + cesu8_string_size; ecma_length_t calculated_length = 0; ecma_length_t code_units_count = 0; while (curr_p < end_p) { code_units[code_units_count] = lit_utf8_peek_next (curr_p); saved_positions[code_units_count] = curr_p; code_units_count++; calculated_length++; lit_utf8_incr (&curr_p); } JERRY_ASSERT (length == calculated_length); if (code_units_count > 0) { for (int j = 0; j < test_subiters; j++) { ecma_length_t index = (ecma_length_t) rand () % code_units_count; curr_p = saved_positions[index]; JERRY_ASSERT (lit_utf8_peek_next (curr_p) == code_units[index]); } } curr_p = (lit_utf8_byte_t *) end_p; while (curr_p > cesu8_string) { JERRY_ASSERT (code_units_count > 0); calculated_length--; JERRY_ASSERT (code_units[calculated_length] == lit_utf8_peek_prev (curr_p)); lit_utf8_decr (&curr_p); } JERRY_ASSERT (calculated_length == 0); while (curr_p < end_p) { ecma_char_t code_unit = lit_utf8_read_next (&curr_p); JERRY_ASSERT (code_unit == code_units[calculated_length]); calculated_length++; } JERRY_ASSERT (length == calculated_length); while (curr_p > cesu8_string) { JERRY_ASSERT (code_units_count > 0); calculated_length--; JERRY_ASSERT (code_units[calculated_length] == lit_utf8_read_prev (&curr_p)); } JERRY_ASSERT (calculated_length == 0); } /* Overlong-encoded code point */ lit_utf8_byte_t invalid_cesu8_string_1[] = {0xC0, 0x82}; JERRY_ASSERT (!lit_is_cesu8_string_valid (invalid_cesu8_string_1, sizeof (invalid_cesu8_string_1))); /* Overlong-encoded code point */ lit_utf8_byte_t invalid_cesu8_string_2[] = {0xE0, 0x80, 0x81}; JERRY_ASSERT (!lit_is_cesu8_string_valid (invalid_cesu8_string_2, sizeof (invalid_cesu8_string_2))); /* Pair of surrogates: 0xD901 0xDFF0 which encode Unicode character 0x507F0 */ lit_utf8_byte_t invalid_cesu8_string_3[] = {0xED, 0xA4, 0x81, 0xED, 0xBF, 0xB0}; JERRY_ASSERT (lit_is_cesu8_string_valid (invalid_cesu8_string_3, sizeof (invalid_cesu8_string_3))); /* Isolated high surrogate 0xD901 */ lit_utf8_byte_t valid_utf8_string_1[] = {0xED, 0xA4, 0x81}; JERRY_ASSERT (lit_is_cesu8_string_valid (valid_utf8_string_1, sizeof (valid_utf8_string_1))); lit_utf8_byte_t res_buf[3]; lit_utf8_size_t res_size; res_size = lit_code_unit_to_utf8 (0x73, res_buf); JERRY_ASSERT (res_size == 1); JERRY_ASSERT (res_buf[0] == 0x73); res_size = lit_code_unit_to_utf8 (0x41A, res_buf); JERRY_ASSERT (res_size == 2); JERRY_ASSERT (res_buf[0] == 0xD0); JERRY_ASSERT (res_buf[1] == 0x9A); res_size = lit_code_unit_to_utf8 (0xD7FF, res_buf); JERRY_ASSERT (res_size == 3); JERRY_ASSERT (res_buf[0] == 0xED); JERRY_ASSERT (res_buf[1] == 0x9F); JERRY_ASSERT (res_buf[2] == 0xBF); ecma_finalize (); lit_finalize (); jmem_finalize (true); return 0; } /* main */
/** * Read the input pattern and parse the range of character class * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t re_parse_char_class (re_parser_ctx_t *parser_ctx_p, /**< number of classes */ re_char_class_callback append_char_class, /**< callback function, * which adds the char-ranges * to the bytecode */ void *re_ctx_p, /**< regexp compiler context */ re_token_t *out_token_p) /**< out: output token */ { re_token_type_t token_type = ((re_compiler_ctx_t *) re_ctx_p)->current_token.type; out_token_p->qmax = out_token_p->qmin = 1; uint32_t start = RE_CHAR_UNDEF; bool is_range = false; parser_ctx_p->num_of_classes = 0; if (lit_utf8_peek_prev (parser_ctx_p->input_curr_p) != LIT_CHAR_LEFT_SQUARE) { lit_utf8_decr (&parser_ctx_p->input_curr_p); lit_utf8_decr (&parser_ctx_p->input_curr_p); } do { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class, end of string"); } uint32_t ch = lit_utf8_read_next (&parser_ctx_p->input_curr_p); if (ch == LIT_CHAR_RIGHT_SQUARE) { if (start != RE_CHAR_UNDEF) { append_char_class (re_ctx_p, start, start); } break; } else if (ch == LIT_CHAR_MINUS) { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class, end of string after '-'"); } if (start != RE_CHAR_UNDEF && !is_range && *parser_ctx_p->input_curr_p != LIT_CHAR_RIGHT_SQUARE) { is_range = true; continue; } } else if (ch == LIT_CHAR_BACKSLASH) { if (parser_ctx_p->input_curr_p >= parser_ctx_p->input_end_p) { return ecma_raise_syntax_error ("invalid character class, end of string after '\\'"); } ch = *parser_ctx_p->input_curr_p++; if (ch == LIT_CHAR_LOWERCASE_B) { ch = LIT_CHAR_BS; } else if (ch == LIT_CHAR_LOWERCASE_F) { ch = LIT_CHAR_FF; } else if (ch == LIT_CHAR_LOWERCASE_N) { ch = LIT_CHAR_LF; } else if (ch == LIT_CHAR_LOWERCASE_T) { ch = LIT_CHAR_TAB; } else if (ch == LIT_CHAR_LOWERCASE_R) { ch = LIT_CHAR_CR; } else if (ch == LIT_CHAR_LOWERCASE_V) { ch = LIT_CHAR_VTAB; } else if (ch == LIT_CHAR_LOWERCASE_C) { if (parser_ctx_p->input_curr_p < parser_ctx_p->input_end_p) { ch = *parser_ctx_p->input_curr_p; if ((ch >= LIT_CHAR_ASCII_UPPERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_UPPERCASE_LETTERS_END) || (ch >= LIT_CHAR_ASCII_LOWERCASE_LETTERS_BEGIN && ch <= LIT_CHAR_ASCII_LOWERCASE_LETTERS_END) || (ch >= LIT_CHAR_0 && ch <= LIT_CHAR_9)) { /* See ECMA-262 v5, 15.10.2.10 (Point 3) */ ch = (ch % 32); parser_ctx_p->input_curr_p++; } else { ch = LIT_CHAR_LOWERCASE_C; } } } else if (ch == LIT_CHAR_LOWERCASE_X) { lit_code_point_t code_point; if (!lit_read_code_point_from_hex (parser_ctx_p->input_curr_p, 2, &code_point)) { return ecma_raise_syntax_error ("invalid character class, end of string after '\\x'"); } parser_ctx_p->input_curr_p += 2; append_char_class (re_ctx_p, code_point, code_point); } else if (ch == LIT_CHAR_LOWERCASE_U) { lit_code_point_t code_point; if (!lit_read_code_point_from_hex (parser_ctx_p->input_curr_p, 4, &code_point)) { return ecma_raise_syntax_error ("invalid character class, end of string after '\\u'"); } parser_ctx_p->input_curr_p += 4; append_char_class (re_ctx_p, code_point, code_point); } else if (ch == LIT_CHAR_LOWERCASE_D) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_ASCII_DIGITS_BEGIN, LIT_CHAR_ASCII_DIGITS_END); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_UPPERCASE_D) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_ASCII_DIGITS_BEGIN - 1); append_char_class (re_ctx_p, LIT_CHAR_ASCII_DIGITS_END + 1, LIT_UTF16_CODE_UNIT_MAX); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_LOWERCASE_S) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_TAB, LIT_CHAR_CR); append_char_class (re_ctx_p, LIT_CHAR_SP, LIT_CHAR_SP); append_char_class (re_ctx_p, LIT_CHAR_NBSP, LIT_CHAR_NBSP); append_char_class (re_ctx_p, 0x1680UL, 0x1680UL); /* Ogham Space Mark */ append_char_class (re_ctx_p, 0x180EUL, 0x180EUL); /* Mongolian Vowel Separator */ append_char_class (re_ctx_p, 0x2000UL, 0x200AUL); /* En Quad - Hair Space */ append_char_class (re_ctx_p, LIT_CHAR_LS, LIT_CHAR_PS); append_char_class (re_ctx_p, 0x202FUL, 0x202FUL); /* Narrow No-Break Space */ append_char_class (re_ctx_p, 0x205FUL, 0x205FUL); /* Medium Mathematical Space */ append_char_class (re_ctx_p, 0x3000UL, 0x3000UL); /* Ideographic Space */ append_char_class (re_ctx_p, LIT_CHAR_BOM, LIT_CHAR_BOM); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_UPPERCASE_S) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_TAB - 1); append_char_class (re_ctx_p, LIT_CHAR_CR + 1, LIT_CHAR_SP - 1); append_char_class (re_ctx_p, LIT_CHAR_SP + 1, LIT_CHAR_NBSP - 1); append_char_class (re_ctx_p, LIT_CHAR_NBSP + 1, 0x167FUL); append_char_class (re_ctx_p, 0x1681UL, 0x180DUL); append_char_class (re_ctx_p, 0x180FUL, 0x1FFFUL); append_char_class (re_ctx_p, 0x200BUL, LIT_CHAR_LS - 1); append_char_class (re_ctx_p, LIT_CHAR_PS + 1, 0x202EUL); append_char_class (re_ctx_p, 0x2030UL, 0x205EUL); append_char_class (re_ctx_p, 0x2060UL, 0x2FFFUL); append_char_class (re_ctx_p, 0x3001UL, LIT_CHAR_BOM - 1); append_char_class (re_ctx_p, LIT_CHAR_BOM + 1, LIT_UTF16_CODE_UNIT_MAX); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_LOWERCASE_W) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_0, LIT_CHAR_9); append_char_class (re_ctx_p, LIT_CHAR_UPPERCASE_A, LIT_CHAR_UPPERCASE_Z); append_char_class (re_ctx_p, LIT_CHAR_UNDERSCORE, LIT_CHAR_UNDERSCORE); append_char_class (re_ctx_p, LIT_CHAR_LOWERCASE_A, LIT_CHAR_LOWERCASE_Z); ch = RE_CHAR_UNDEF; } else if (ch == LIT_CHAR_UPPERCASE_W) { /* See ECMA-262 v5, 15.10.2.12 */ append_char_class (re_ctx_p, LIT_CHAR_NULL, LIT_CHAR_0 - 1); append_char_class (re_ctx_p, LIT_CHAR_9 + 1, LIT_CHAR_UPPERCASE_A - 1); append_char_class (re_ctx_p, LIT_CHAR_UPPERCASE_Z + 1, LIT_CHAR_UNDERSCORE - 1); append_char_class (re_ctx_p, LIT_CHAR_UNDERSCORE + 1, LIT_CHAR_LOWERCASE_A - 1); append_char_class (re_ctx_p, LIT_CHAR_LOWERCASE_Z + 1, LIT_UTF16_CODE_UNIT_MAX); ch = RE_CHAR_UNDEF; } else if (ch <= LIT_UTF16_CODE_UNIT_MAX && lit_char_is_octal_digit ((ecma_char_t) ch) && ch != LIT_CHAR_0) { parser_ctx_p->input_curr_p--; ch = re_parse_octal (parser_ctx_p); } } /* ch == LIT_CHAR_BACKSLASH */ if (ch == RE_CHAR_UNDEF) { if (start != RE_CHAR_UNDEF) { if (is_range) { return ecma_raise_syntax_error ("invalid character class, invalid range"); } else { append_char_class (re_ctx_p, start, start); start = RE_CHAR_UNDEF; } } } else { if (start != RE_CHAR_UNDEF) { if (is_range) { if (start > ch) { return ecma_raise_syntax_error ("invalid character class, wrong order"); } else { append_char_class (re_ctx_p, start, ch); start = RE_CHAR_UNDEF; is_range = false; } } else { append_char_class (re_ctx_p, start, start); start = ch; } } else { start = ch; } } } while (token_type == RE_TOK_START_CHAR_CLASS || token_type == RE_TOK_START_INV_CHAR_CLASS); return re_parse_iterator (parser_ctx_p, out_token_p); } /* re_parse_char_class */