1 | /* Copyright JS Foundation and other contributors, http://js.foundation |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
4 | * you may not use this file except in compliance with the License. |
5 | * You may obtain a copy of the License at |
6 | * |
7 | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software |
10 | * distributed under the License is distributed on an "AS IS" BASIS |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | * See the License for the specific language governing permissions and |
13 | * limitations under the License. |
14 | */ |
15 | |
16 | #include "jerryscript-ext/arg.h" |
17 | #include "jerryscript.h" |
18 | #include "arg-internal.h" |
19 | #include "jext-common.h" |
20 | |
21 | JERRYX_STATIC_ASSERT (sizeof (jerryx_arg_int_option_t) <= sizeof (((jerryx_arg_t *) 0)->extra_info), |
22 | jerryx_arg_number_options_t_must_fit_into_extra_info); |
23 | |
24 | /** |
25 | * Validate the JS arguments and assign them to the native arguments. |
26 | * |
27 | * @return jerry undefined: all validators passed, |
28 | * jerry error: a validator failed. |
29 | */ |
30 | jerry_value_t |
31 | jerryx_arg_transform_args (const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */ |
32 | const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */ |
33 | const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */ |
34 | jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */ |
35 | { |
36 | jerry_value_t ret = jerry_create_undefined (); |
37 | |
38 | jerryx_arg_js_iterator_t iterator = |
39 | { |
40 | .js_arg_p = js_arg_p, |
41 | .js_arg_cnt = js_arg_cnt, |
42 | .js_arg_idx = 0 |
43 | }; |
44 | |
45 | for (; c_arg_cnt != 0 && !jerry_value_is_error (ret); c_arg_cnt--, c_arg_p++) |
46 | { |
47 | ret = c_arg_p->func (&iterator, c_arg_p); |
48 | } |
49 | |
50 | return ret; |
51 | } /* jerryx_arg_transform_args */ |
52 | |
53 | /** |
54 | * Validate the this value and the JS arguments, |
55 | * and assign them to the native arguments. |
56 | * This function is useful to perform input validation inside external |
57 | * function handlers (see jerry_external_handler_t). |
58 | * @note this_val is processed as the first value, before the array of arguments. |
59 | * |
60 | * @return jerry undefined: all validators passed, |
61 | * jerry error: a validator failed. |
62 | */ |
63 | jerry_value_t |
64 | jerryx_arg_transform_this_and_args (const jerry_value_t this_val, /**< the this_val for the external function */ |
65 | const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */ |
66 | const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */ |
67 | const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */ |
68 | jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */ |
69 | { |
70 | if (c_arg_cnt == 0) |
71 | { |
72 | return jerry_create_undefined (); |
73 | } |
74 | |
75 | jerryx_arg_js_iterator_t iterator = |
76 | { |
77 | .js_arg_p = &this_val, |
78 | .js_arg_cnt = 1, |
79 | .js_arg_idx = 0 |
80 | }; |
81 | |
82 | jerry_value_t ret = c_arg_p->func (&iterator, c_arg_p); |
83 | |
84 | if (jerry_value_is_error (ret)) |
85 | { |
86 | jerry_release_value (ret); |
87 | |
88 | return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "'this' validation failed." ); |
89 | } |
90 | |
91 | return jerryx_arg_transform_args (js_arg_p, js_arg_cnt, c_arg_p + 1, c_arg_cnt - 1); |
92 | } /* jerryx_arg_transform_this_and_args */ |
93 | |
94 | /** |
95 | * Validate the `obj_val`'s properties, |
96 | * and assign them to the native arguments. |
97 | * |
98 | * @return jerry undefined: all validators passed, |
99 | * jerry error: a validator failed. |
100 | */ |
101 | jerry_value_t |
102 | jerryx_arg_transform_object_properties (const jerry_value_t obj_val,/**< the JS object */ |
103 | const jerry_char_t **name_p, /**< property name list of the JS object */ |
104 | const jerry_length_t name_cnt, /**< count of the name list */ |
105 | const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */ |
106 | jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */ |
107 | { |
108 | if (!jerry_value_is_object (obj_val)) |
109 | { |
110 | return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an object." ); |
111 | } |
112 | |
113 | JERRY_VLA (jerry_value_t, prop, name_cnt); |
114 | |
115 | for (jerry_length_t i = 0; i < name_cnt; i++, name_p++) |
116 | { |
117 | const jerry_value_t name_str = jerry_create_string (*name_p); |
118 | prop[i] = jerry_get_property (obj_val, name_str); |
119 | jerry_release_value (name_str); |
120 | |
121 | if (jerry_value_is_error (prop[i])) |
122 | { |
123 | for (jerry_length_t j = 0; j < i; j++) |
124 | { |
125 | jerry_release_value (prop[j]); |
126 | } |
127 | |
128 | return prop[i]; |
129 | } |
130 | } |
131 | |
132 | const jerry_value_t ret = jerryx_arg_transform_args (prop, name_cnt, c_arg_p, c_arg_cnt); |
133 | |
134 | for (jerry_length_t i = 0; i < name_cnt; i++) |
135 | { |
136 | jerry_release_value (prop[i]); |
137 | } |
138 | |
139 | return ret; |
140 | } /* jerryx_arg_transform_object_properties */ |
141 | |
142 | /** |
143 | * Validate the items in the JS array and assign them to the native arguments. |
144 | * |
145 | * @return jerry undefined: all validators passed, |
146 | * jerry error: a validator failed. |
147 | */ |
148 | jerry_value_t |
149 | jerryx_arg_transform_array (const jerry_value_t array_val, /**< points to the JS array */ |
150 | const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */ |
151 | jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */ |
152 | { |
153 | if (!jerry_value_is_array (array_val)) |
154 | { |
155 | return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an array." ); |
156 | } |
157 | |
158 | JERRY_VLA (jerry_value_t, arr, c_arg_cnt); |
159 | |
160 | for (jerry_length_t i = 0; i < c_arg_cnt; i++) |
161 | { |
162 | arr[i] = jerry_get_property_by_index (array_val, i); |
163 | |
164 | if (jerry_value_is_error (arr[i])) |
165 | { |
166 | for (jerry_length_t j = 0; j < i; j++) |
167 | { |
168 | jerry_release_value (arr[j]); |
169 | } |
170 | |
171 | return arr[i]; |
172 | } |
173 | } |
174 | |
175 | const jerry_value_t ret = jerryx_arg_transform_args (arr, c_arg_cnt, c_arg_p, c_arg_cnt); |
176 | |
177 | for (jerry_length_t i = 0; i < c_arg_cnt; i++) |
178 | { |
179 | jerry_release_value (arr[i]); |
180 | } |
181 | |
182 | return ret; |
183 | } /* jerryx_arg_transform_array */ |
184 | |