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 "arg-internal.h"
17 #include "jerryscript-ext/arg.h"
18 #include "jerryscript.h"
19 #if defined(JERRY_FOR_IAR_CONFIG)
20 #include "jerryscript-core.h"
21 #endif
22
23 #define JERRYX_STATIC_ASSERT(x, msg) \
24 enum { static_assertion_failed_ ## msg = 1 / (!!(x)) }
25
26 JERRYX_STATIC_ASSERT (sizeof (jerryx_arg_int_option_t) <= sizeof (((jerryx_arg_t *) 0)->extra_info),
27 jerryx_arg_number_options_t_must_fit_into_extra_info);
28
29 #undef JERRYX_STATIC_ASSERT
30
31 /**
32 * Validate the JS arguments and assign them to the native arguments.
33 *
34 * @return jerry undefined: all validators passed,
35 * jerry error: a validator failed.
36 */
37 jerry_value_t
jerryx_arg_transform_args(const jerry_value_t * js_arg_p,const jerry_length_t js_arg_cnt,const jerryx_arg_t * c_arg_p,jerry_length_t c_arg_cnt)38 jerryx_arg_transform_args (const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */
39 const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */
40 const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */
41 jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
42 {
43 jerry_value_t ret = jerry_create_undefined ();
44
45 jerryx_arg_js_iterator_t iterator =
46 {
47 .js_arg_p = js_arg_p,
48 .js_arg_cnt = js_arg_cnt,
49 .js_arg_idx = 0
50 };
51
52 for (; c_arg_cnt != 0 && !jerry_value_is_error (ret); c_arg_cnt--, c_arg_p++)
53 {
54 ret = c_arg_p->func (&iterator, c_arg_p);
55 }
56
57 return ret;
58 } /* jerryx_arg_transform_args */
59
60 /**
61 * Validate the this value and the JS arguments,
62 * and assign them to the native arguments.
63 * This function is useful to perform input validation inside external
64 * function handlers (see jerry_external_handler_t).
65 * @note this_val is processed as the first value, before the array of arguments.
66 *
67 * @return jerry undefined: all validators passed,
68 * jerry error: a validator failed.
69 */
70 jerry_value_t
jerryx_arg_transform_this_and_args(const jerry_value_t this_val,const jerry_value_t * js_arg_p,const jerry_length_t js_arg_cnt,const jerryx_arg_t * c_arg_p,jerry_length_t c_arg_cnt)71 jerryx_arg_transform_this_and_args (const jerry_value_t this_val, /**< the this_val for the external function */
72 const jerry_value_t *js_arg_p, /**< points to the array with JS arguments */
73 const jerry_length_t js_arg_cnt, /**< the count of the `js_arg_p` array */
74 const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */
75 jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
76 {
77 if (c_arg_cnt == 0)
78 {
79 return jerry_create_undefined ();
80 }
81
82 jerryx_arg_js_iterator_t iterator =
83 {
84 .js_arg_p = &this_val,
85 .js_arg_cnt = 1,
86 .js_arg_idx = 0
87 };
88
89 jerry_value_t ret = c_arg_p->func (&iterator, c_arg_p);
90
91 if (jerry_value_is_error (ret))
92 {
93 jerry_release_value (ret);
94
95 return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "'this' validation failed.");
96 }
97
98 return jerryx_arg_transform_args (js_arg_p, js_arg_cnt, c_arg_p + 1, c_arg_cnt - 1);
99 } /* jerryx_arg_transform_this_and_args */
100
101 /**
102 * Validate the `obj_val`'s properties,
103 * and assign them to the native arguments.
104 *
105 * @return jerry undefined: all validators passed,
106 * jerry error: a validator failed.
107 */
108 jerry_value_t
jerryx_arg_transform_object_properties(const jerry_value_t obj_val,const jerry_char_t ** name_p,const jerry_length_t name_cnt,const jerryx_arg_t * c_arg_p,jerry_length_t c_arg_cnt)109 jerryx_arg_transform_object_properties (const jerry_value_t obj_val,/**< the JS object */
110 const jerry_char_t **name_p, /**< property name list of the JS object */
111 const jerry_length_t name_cnt, /**< count of the name list */
112 const jerryx_arg_t *c_arg_p, /**< points to the array of transformation steps */
113 jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
114 {
115 #if defined(JERRY_FOR_IAR_CONFIG)
116 jerry_value_t* prop;
117 jerry_value_t prop_i;
118 #endif
119 if (!jerry_value_is_object (obj_val))
120 {
121 return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an object.");
122 }
123
124 #if defined(JERRY_FOR_IAR_CONFIG)
125 prop = (jerry_value_t*) jerry_vla_malloc (sizeof(jerry_value_t) * name_cnt);
126 if (!prop)
127 {
128 return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "malloc prop fail.");
129 }
130 #else
131 JERRY_VLA (jerry_value_t, prop, name_cnt);
132 #endif
133 for (jerry_length_t i = 0; i < name_cnt; i++, name_p++)
134 {
135 const jerry_value_t name_str = jerry_create_string (*name_p);
136 prop[i] = jerry_get_property (obj_val, name_str);
137 jerry_release_value (name_str);
138
139 if (jerry_value_is_error (prop[i]))
140 {
141 for (jerry_length_t j = 0; j < i; j++)
142 {
143 jerry_release_value (prop[j]);
144 }
145 #if defined(JERRY_FOR_IAR_CONFIG)
146 prop_i = prop[i];
147 jerry_vla_free ((char*)prop);
148 return prop_i;
149 #else
150 return prop[i];
151 #endif
152 }
153 }
154
155 const jerry_value_t ret = jerryx_arg_transform_args (prop, name_cnt, c_arg_p, c_arg_cnt);
156
157 for (jerry_length_t i = 0; i < name_cnt; i++)
158 {
159 jerry_release_value (prop[i]);
160 }
161 #if defined(JERRY_FOR_IAR_CONFIG)
162 jerry_vla_free ((char*)prop);
163 #endif
164 return ret;
165 } /* jerryx_arg_transform_object_properties */
166
167 /**
168 * Validate the items in the JS array and assign them to the native arguments.
169 *
170 * @return jerry undefined: all validators passed,
171 * jerry error: a validator failed.
172 */
173 jerry_value_t
jerryx_arg_transform_array(const jerry_value_t array_val,const jerryx_arg_t * c_arg_p,jerry_length_t c_arg_cnt)174 jerryx_arg_transform_array (const jerry_value_t array_val, /**< points to the JS array */
175 const jerryx_arg_t *c_arg_p, /**< points to the array of validation/transformation steps */
176 jerry_length_t c_arg_cnt) /**< the count of the `c_arg_p` array */
177 {
178 #if defined(JERRY_FOR_IAR_CONFIG)
179 jerry_value_t* arr;
180 jerry_value_t arr_i;
181 #endif
182 if (!jerry_value_is_array (array_val))
183 {
184 return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "Not an array.");
185 }
186
187 #if defined(JERRY_FOR_IAR_CONFIG)
188 arr = (jerry_value_t*) jerry_vla_malloc (sizeof(jerry_value_t) * c_arg_cnt);
189 if (!arr)
190 {
191 return jerry_create_error (JERRY_ERROR_TYPE, (jerry_char_t *) "malloc arr fail.");
192 }
193 #else
194 JERRY_VLA (jerry_value_t, arr, c_arg_cnt);
195 #endif
196 for (jerry_length_t i = 0; i < c_arg_cnt; i++)
197 {
198 arr[i] = jerry_get_property_by_index (array_val, i);
199
200 if (jerry_value_is_error (arr[i]))
201 {
202 for (jerry_length_t j = 0; j < i; j++)
203 {
204 jerry_release_value (arr[j]);
205 }
206 #if defined(JERRY_FOR_IAR_CONFIG)
207 arr_i = arr[i];
208 jerry_vla_free ((char*)arr);
209 return arr_i;
210 #else
211 return arr[i];
212 #endif
213 }
214 }
215
216 const jerry_value_t ret = jerryx_arg_transform_args (arr, c_arg_cnt, c_arg_p, c_arg_cnt);
217
218 for (jerry_length_t i = 0; i < c_arg_cnt; i++)
219 {
220 jerry_release_value (arr[i]);
221 }
222 #if defined(JERRY_FOR_IAR_CONFIG)
223 jerry_vla_free ((char*)arr);
224 #endif
225 return ret;
226 } /* jerryx_arg_transform_array */
227