From 4e7a9d2d53804c1af7f7f7c57e2f6640898d0807 Mon Sep 17 00:00:00 2001 From: Zidong Jiang Date: Mon, 8 Jan 2018 17:17:40 +0800 Subject: [PATCH] [jerryx/arg]add jerryx_arg_utf8_string (#2133) JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com --- docs/09.EXT-REFERENCE-ARG.md | 33 ++++- jerry-ext/arg/arg-transform-functions.c | 126 +++++++++++++++---- jerry-ext/include/jerryscript-ext/arg.h | 2 + jerry-ext/include/jerryscript-ext/arg.impl.h | 46 +++++++ tests/unit-ext/test-ext-arg.c | 27 ++++ 5 files changed, 212 insertions(+), 22 deletions(-) diff --git a/docs/09.EXT-REFERENCE-ARG.md b/docs/09.EXT-REFERENCE-ARG.md index 00136f20c..715dc04be 100644 --- a/docs/09.EXT-REFERENCE-ARG.md +++ b/docs/09.EXT-REFERENCE-ARG.md @@ -28,6 +28,7 @@ typedef struct - [jerryx_arg_number](#jerryx_arg_number) - [jerryx_arg_boolean](#jerryx_arg_boolean) - [jerryx_arg_string](#jerryx_arg_string) +- [jerryx_arg_utf8_string](#jerryx_arg_utf8_string) - [jerryx_arg_function](#jerryx_arg_function) - [jerryx_arg_native_pointer](#jerryx_arg_native_pointer) - [jerryx_arg_ignore](#jerryx_arg_ignore) @@ -461,7 +462,7 @@ jerryx_arg_boolean (bool *dest, **Summary** Create a validation/transformation step (`jerryx_arg_t`) that expects to -consume one `string` JS argument and stores it into a C `char` array. +consume one `string` JS argument and stores it into a CESU-8 C `char` array. **Prototype** @@ -482,6 +483,36 @@ jerryx_arg_string (char *dest, **See also** - [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args) +- [jerry_arg_utf8_string](#jerry_arg_utf8_string) + + +## jerryx_arg_utf8_string + +**Summary** + +Create a validation/transformation step (`jerryx_arg_t`) that expects to +consume one `string` JS argument and stores it into a UTF-8 C `char` array. + +**Prototype** + +```c +static inline jerryx_arg_t +jerryx_arg_utf8_string (char *dest, + uint32_t size, + jerryx_arg_coerce_t coerce_flag, + jerryx_arg_optional_t opt_flag) +``` + + - return value - the created `jerryx_arg_t` instance. + - `dest` - pointer to the native char array where the result should be stored. + - `size` - the size of native char array. + - `coerce_flag` - whether type coercion is allowed. + - `opt_flag` - whether the argument is optional. + +**See also** + +- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args) +- [jerry_arg_string](#jerry_arg_string) ## jerryx_arg_function diff --git a/jerry-ext/arg/arg-transform-functions.c b/jerry-ext/arg/arg-transform-functions.c index bc566d854..e71b34ab0 100644 --- a/jerry-ext/arg/arg-transform-functions.c +++ b/jerry-ext/arg/arg-transform-functions.c @@ -107,7 +107,7 @@ jerryx_arg_transform_number_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /** } /* jerryx_arg_transform_number_strict */ /** - * Tranform a JS argument to a double. Type coercion is allowed. + * Transform a JS argument to a double. Type coercion is allowed. * * @return jerry undefined: the transformer passes, * jerry error: the transformer fails. @@ -206,7 +206,7 @@ JERRYX_ARG_TRANSFORM_FUNC_FOR_INT (int32, INT32_MIN, INT32_MAX) #undef JERRYX_ARG_TRANSFORM_FUNC_FOR_INT_TEMPLATE #undef JERRYX_ARG_TRANSFORM_FUNC_FOR_INT /** - * Tranform a JS argument to a boolean. Type coercion is not allowed. + * Transform a JS argument to a boolean. Type coercion is not allowed. * * @return jerry undefined: the transformer passes, * jerry error: the transformer fails. @@ -230,7 +230,7 @@ jerryx_arg_transform_boolean_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /* } /* jerryx_arg_transform_boolean_strict */ /** - * Tranform a JS argument to a boolean. Type coercion is allowed. + * Transform a JS argument to a boolean. Type coercion is allowed. * * @return jerry undefined: the transformer passes, * jerry error: the transformer fails. @@ -251,21 +251,37 @@ jerryx_arg_transform_boolean (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< avai /** * The common routine for string transformer. + * It works for both CESU-8 and UTF-8 string. * * @return jerry undefined: the transformer passes, * jerry error: the transformer fails. */ static jerry_value_t -jerryx_arg_string_common_routine (jerry_value_t js_arg, /**< JS arg */ - const jerryx_arg_t *c_arg_p) /**< native arg */ +jerryx_arg_string_to_buffer_common_routine (jerry_value_t js_arg, /**< JS arg */ + const jerryx_arg_t *c_arg_p, /**< native arg */ + bool is_utf8) /**< whether it is UTF-8 string */ { jerry_char_t *target_p = (jerry_char_t *) c_arg_p->dest; jerry_size_t target_buf_size = (jerry_size_t) c_arg_p->extra_info; - jerry_size_t size = jerry_string_to_char_buffer (js_arg, - target_p, - target_buf_size); + jerry_size_t size; + jerry_length_t len; - if ((size == target_buf_size) || (size == 0 && jerry_get_string_length (js_arg) != 0)) + if (!is_utf8) + { + size = jerry_string_to_char_buffer (js_arg, + target_p, + target_buf_size); + len = jerry_get_string_length (js_arg); + } + else + { + size = jerry_string_to_utf8_char_buffer (js_arg, + target_p, + target_buf_size); + len = jerry_get_utf8_string_length (js_arg); + } + + if ((size == target_buf_size) || (size == 0 && len != 0)) { return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Buffer size is not large enough."); @@ -274,17 +290,18 @@ jerryx_arg_string_common_routine (jerry_value_t js_arg, /**< JS arg */ target_p[size] = '\0'; return jerry_create_undefined (); -} /* jerryx_arg_string_common_routine */ +} /* jerryx_arg_string_to_buffer_common_routine */ /** - * Tranform a JS argument to a char array. Type coercion is not allowed. + * Transform a JS argument to a UTF-8/CESU-8 char array. Type coercion is not allowed. * * @return jerry undefined: the transformer passes, * jerry error: the transformer fails. */ -jerry_value_t -jerryx_arg_transform_string_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ - const jerryx_arg_t *c_arg_p) /**< the native arg */ +static jerry_value_t +jerryx_arg_transform_string_strict_common (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ + const jerryx_arg_t *c_arg_p, /**< the native arg */ + bool is_utf8) /**< whether it is a UTF-8 string */ { jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p); @@ -294,18 +311,19 @@ jerryx_arg_transform_string_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /** (jerry_char_t *) "It is not a string."); } - return jerryx_arg_string_common_routine (js_arg, c_arg_p); -} /* jerryx_arg_transform_string_strict */ + return jerryx_arg_string_to_buffer_common_routine (js_arg, c_arg_p, is_utf8); +} /* jerryx_arg_transform_string_strict_common */ /** - * Tranform a JS argument to a char array. Type coercion is allowed. + * Transform a JS argument to a UTF-8/CESU-8 char array. Type coercion is allowed. * * @return jerry undefined: the transformer passes, * jerry error: the transformer fails. */ -jerry_value_t -jerryx_arg_transform_string (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ - const jerryx_arg_t *c_arg_p) /**< the native arg */ +static jerry_value_t +jerryx_arg_transform_string_common (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ + const jerryx_arg_t *c_arg_p, /**< the native arg */ + bool is_utf8) /**< whether it is a UTF-8 string */ { jerry_value_t js_arg = jerryx_arg_js_iterator_pop (js_arg_iter_p); @@ -319,12 +337,76 @@ jerryx_arg_transform_string (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< avail (jerry_char_t *) "It can not be converted to a string."); } - jerry_value_t ret = jerryx_arg_string_common_routine (to_string, c_arg_p); + jerry_value_t ret = jerryx_arg_string_to_buffer_common_routine (to_string, c_arg_p, is_utf8); jerry_release_value (to_string); return ret; +} /* jerryx_arg_transform_string_common */ + +/** + * Transform a JS argument to a cesu8 char array. Type coercion is not allowed. + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return jerry undefined: the transformer passes, + * jerry error: the transformer fails. + */ +jerry_value_t +jerryx_arg_transform_string_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ + const jerryx_arg_t *c_arg_p) /**< the native arg */ +{ + return jerryx_arg_transform_string_strict_common (js_arg_iter_p, c_arg_p, false); +} /* jerryx_arg_transform_string_strict */ + +/** + * Transform a JS argument to a utf8 char array. Type coercion is not allowed. + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return jerry undefined: the transformer passes, + * jerry error: the transformer fails. + */ +jerry_value_t +jerryx_arg_transform_utf8_string_strict (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ + const jerryx_arg_t *c_arg_p) /**< the native arg */ +{ + return jerryx_arg_transform_string_strict_common (js_arg_iter_p, c_arg_p, true); +} /* jerryx_arg_transform_utf8_string_strict */ + +/** + * Transform a JS argument to a cesu8 char array. Type coercion is allowed. + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return jerry undefined: the transformer passes, + * jerry error: the transformer fails. + */ +jerry_value_t +jerryx_arg_transform_string (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ + const jerryx_arg_t *c_arg_p) /**< the native arg */ +{ + return jerryx_arg_transform_string_common (js_arg_iter_p, c_arg_p, false); } /* jerryx_arg_transform_string */ +/** + * Transform a JS argument to a utf8 char array. Type coercion is allowed. + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return jerry undefined: the transformer passes, + * jerry error: the transformer fails. + */ +jerry_value_t +jerryx_arg_transform_utf8_string (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ + const jerryx_arg_t *c_arg_p) /**< the native arg */ +{ + return jerryx_arg_transform_string_common (js_arg_iter_p, c_arg_p, true); +} /* jerryx_arg_transform_utf8_string */ + /** * Check whether the JS argument is jerry function, if so, assign to the native argument. * @@ -440,6 +522,8 @@ JERRYX_ARG_TRANSFORM_OPTIONAL (boolean) JERRYX_ARG_TRANSFORM_OPTIONAL (boolean_strict) JERRYX_ARG_TRANSFORM_OPTIONAL (string) JERRYX_ARG_TRANSFORM_OPTIONAL (string_strict) +JERRYX_ARG_TRANSFORM_OPTIONAL (utf8_string) +JERRYX_ARG_TRANSFORM_OPTIONAL (utf8_string_strict) JERRYX_ARG_TRANSFORM_OPTIONAL (function) JERRYX_ARG_TRANSFORM_OPTIONAL (native_pointer) JERRYX_ARG_TRANSFORM_OPTIONAL (object_props) diff --git a/jerry-ext/include/jerryscript-ext/arg.h b/jerry-ext/include/jerryscript-ext/arg.h index af81c8c2d..c239aab57 100644 --- a/jerry-ext/include/jerryscript-ext/arg.h +++ b/jerry-ext/include/jerryscript-ext/arg.h @@ -165,6 +165,8 @@ jerryx_arg_boolean (bool *dest, jerryx_arg_coerce_t coerce_flag, jerryx_arg_opti static inline jerryx_arg_t jerryx_arg_string (char *dest, uint32_t size, jerryx_arg_coerce_t coerce_flag, jerryx_arg_optional_t opt_flag); static inline jerryx_arg_t +jerryx_arg_utf8_string (char *dest, uint32_t size, jerryx_arg_coerce_t coerce_flag, jerryx_arg_optional_t opt_flag); +static inline jerryx_arg_t jerryx_arg_function (jerry_value_t *dest, jerryx_arg_optional_t opt_flag); static inline jerryx_arg_t jerryx_arg_native_pointer (void **dest, const jerry_object_native_info_t *info_p, jerryx_arg_optional_t opt_flag); diff --git a/jerry-ext/include/jerryscript-ext/arg.impl.h b/jerry-ext/include/jerryscript-ext/arg.impl.h index 371b31088..47a75f6a6 100644 --- a/jerry-ext/include/jerryscript-ext/arg.impl.h +++ b/jerry-ext/include/jerryscript-ext/arg.impl.h @@ -36,6 +36,7 @@ JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL_AND_STRICT (uint32) JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL_AND_STRICT (int32) JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL_AND_STRICT (number) JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL_AND_STRICT (string) +JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL_AND_STRICT (utf8_string) JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL_AND_STRICT (boolean) JERRYX_ARG_TRANSFORM_FUNC_WITH_OPTIONAL (function) @@ -242,6 +243,51 @@ jerryx_arg_string (char *dest, /**< pointer to the native char array where the r }; } /* jerryx_arg_string */ +/** + * Create a validation/transformation step (`jerryx_arg_t`) that expects to + * consume one `string` JS argument and stores it into a C utf8 `char` array. + * + * @return a jerryx_arg_t instance. + */ +static inline jerryx_arg_t +jerryx_arg_utf8_string (char *dest, /**< [out] pointer to the native char array where the result should be stored */ + uint32_t size, /**< the size of native char array */ + jerryx_arg_coerce_t coerce_flag, /**< whether type coercion is allowed */ + jerryx_arg_optional_t opt_flag) /**< whether the argument is optional */ +{ + jerryx_arg_transform_func_t func; + + if (coerce_flag == JERRYX_ARG_NO_COERCE) + { + if (opt_flag == JERRYX_ARG_OPTIONAL) + { + func = jerryx_arg_transform_utf8_string_strict_optional; + } + else + { + func = jerryx_arg_transform_utf8_string_strict; + } + } + else + { + if (opt_flag == JERRYX_ARG_OPTIONAL) + { + func = jerryx_arg_transform_utf8_string_optional; + } + else + { + func = jerryx_arg_transform_utf8_string; + } + } + + return (jerryx_arg_t) + { + .func = func, + .dest = (void *) dest, + .extra_info = (uintptr_t) size + }; +} /* jerryx_arg_utf8_string */ + /** * Create a validation/transformation step (`jerryx_arg_t`) that expects to * consume one `function` JS argument and stores it into a C `jerry_value_t`. diff --git a/tests/unit-ext/test-ext-arg.c b/tests/unit-ext/test-ext-arg.c index 55f00f481..5ccfad4fb 100644 --- a/tests/unit-ext/test-ext-arg.c +++ b/tests/unit-ext/test-ext-arg.c @@ -563,6 +563,31 @@ test_validator_array2_handler (const jerry_value_t func_obj_val __attribute__((u return jerry_create_undefined (); } /* test_validator_array2_handler */ +static void +test_utf8_string (void) +{ + /* test string: 'str: {DESERET CAPITAL LETTER LONG I}' */ + jerry_value_t str = jerry_create_string ((jerry_char_t *) "\x73\x74\x72\x3a \xed\xa0\x81\xed\xb0\x80"); + char expect_utf8_buf[] = "\x73\x74\x72\x3a \xf0\x90\x90\x80"; + size_t buf_len = strlen (expect_utf8_buf); + char buf[buf_len+1]; + + jerryx_arg_t mapping[] = + { + jerryx_arg_utf8_string (buf, (uint32_t) buf_len + 1, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED), + }; + + jerry_value_t is_ok = jerryx_arg_transform_args (&str, + 1, + mapping, + ARRAY_SIZE (mapping)); + + TEST_ASSERT (!jerry_value_has_error_flag (is_ok)); + TEST_ASSERT (!strcmp (buf, expect_utf8_buf)); + + jerry_release_value (str); +} /* test_utf8_string */ + static jerry_value_t create_object_a_handler (const jerry_value_t func_obj_val __attribute__((unused)), /**< function object */ const jerry_value_t this_val, /**< this value */ @@ -620,6 +645,8 @@ main (void) { jerry_init (JERRY_INIT_EMPTY); + test_utf8_string (); + register_js_function ("test_validator1", test_validator1_handler); register_js_function ("test_validator2", test_validator2_handler); register_js_function ("test_validator_int1", test_validator_int1_handler);