don't crash when loading images > 65kB (fixes #13529)
[swfdec.git] / libswfdec / swfdec_as_function.c
blobca1b735c15d691b36e5f32a9579589bb02cf6c1d
1 /* Swfdec
2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "swfdec_as_function.h"
25 #include "swfdec_as_context.h"
26 #include "swfdec_as_frame_internal.h"
27 #include "swfdec_as_internal.h"
28 #include "swfdec_as_stack.h"
29 #include "swfdec_as_super.h"
30 #include "swfdec_as_strings.h"
31 #include "swfdec_debug.h"
33 G_DEFINE_ABSTRACT_TYPE (SwfdecAsFunction, swfdec_as_function, SWFDEC_TYPE_AS_OBJECT)
35 /**
36 * SECTION:SwfdecAsFunction
37 * @title: SwfdecAsFunction
38 * @short_description: script objects that can be executed
40 * Functions is the basic object for executing code in the Swfdec script engine.
41 * There is multiple different variants of functions, such as script-created
42 * ones and native functions.
44 * If you want to create your own functions, you should create native functions.
45 * The easiest way to do this is with swfdec_as_object_add_function() or
46 * swfdec_as_native_function_new().
48 * In Actionscript, every function can be used as a constructor. If you want to
49 * make a native function be used as a constructor for your own #SwfdecAsObject
50 * subclass, have a look at swfdec_as_native_function_set_construct_type().
53 /**
54 * SwfdecAsFunction
56 * This is the base executable object in Swfdec. It is an abstract object. If
57 * you want to create functions yourself, use #SwfdecAsNativeFunction.
60 static void
61 swfdec_as_function_class_init (SwfdecAsFunctionClass *klass)
65 static void
66 swfdec_as_function_init (SwfdecAsFunction *function)
70 /**
71 * swfdec_as_function_set_constructor:
72 * @fun: a #SwfdecAsFunction
74 * Sets the constructor and prototype of @fun. This is a shortcut for calling
75 * swfdec_as_object_set_constructor() with the right arguments.
76 **/
77 void
78 swfdec_as_function_set_constructor (SwfdecAsFunction *fun)
80 SwfdecAsContext *context;
81 SwfdecAsObject *object;
82 SwfdecAsValue val;
84 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (fun));
86 object = SWFDEC_AS_OBJECT (fun);
87 context = object->context;
88 if (context->Function == NULL)
89 return;
91 SWFDEC_AS_VALUE_SET_OBJECT (&val, context->Function);
92 swfdec_as_object_set_variable_and_flags (object, SWFDEC_AS_STR_constructor,
93 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
95 SWFDEC_AS_VALUE_SET_OBJECT (&val, context->Function_prototype);
96 swfdec_as_object_set_variable_and_flags (object, SWFDEC_AS_STR___proto__,
97 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT |
98 SWFDEC_AS_VARIABLE_VERSION_6_UP);
101 SwfdecAsFrame *
102 swfdec_as_function_call_no_preload (SwfdecAsFunction *function,
103 SwfdecAsObject *thisp, guint n_args, const SwfdecAsValue *args,
104 SwfdecAsValue *return_value)
106 SwfdecAsFrame *frame;
107 SwfdecAsFunctionClass *klass;
109 g_return_val_if_fail (SWFDEC_IS_AS_FUNCTION (function), NULL);
110 g_return_val_if_fail (thisp == NULL || SWFDEC_IS_AS_OBJECT (thisp), NULL);
112 /* just to be sure... */
113 if (return_value)
114 SWFDEC_AS_VALUE_SET_UNDEFINED (return_value);
116 klass = SWFDEC_AS_FUNCTION_GET_CLASS (function);
117 g_assert (klass->call);
118 frame = klass->call (function);
119 /* FIXME: figure out what to do in these situations?
120 * It's a problem when called inside swfdec_as_function_call () as the
121 * user of that function expects success, but super may fail here */
122 if (frame == NULL)
123 return NULL;
124 if (function->priv)
125 swfdec_as_frame_set_security (frame, function->priv);
126 /* second check especially for super object */
127 if (thisp != NULL && frame->thisp == NULL) {
128 swfdec_as_frame_set_this (frame, swfdec_as_object_resolve (thisp));
130 frame->is_local = TRUE;
131 frame->argc = n_args;
132 frame->argv = args;
133 frame->return_value = return_value;
134 return frame;
138 * swfdec_as_function_call:
139 * @function: the #SwfdecAsFunction to call
140 * @thisp: this argument to use for the call or %NULL for none
141 * @n_args: number of arguments to pass to the function
142 * @args: the arguments to pass or %NULL to read the last @n_args stack elements.
143 * The memory must be unchanged until the function call has completed.
144 * This is after the call to swfdec_as_context_run () has finished.
145 * @return_value: pointer for return value or %NULL to push the return value to
146 * the stack
148 * Calls the given function. This means a #SwfdecAsFrame is created for the
149 * function and pushed on top of the execution stack. The function is however
150 * not executed. Call swfdec_as_context_run () to execute it.
152 void
153 swfdec_as_function_call (SwfdecAsFunction *function, SwfdecAsObject *thisp, guint n_args,
154 const SwfdecAsValue *args, SwfdecAsValue *return_value)
156 SwfdecAsFrame *frame;
158 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (function));
159 g_return_if_fail (thisp == NULL || SWFDEC_IS_AS_OBJECT (thisp));
161 frame = swfdec_as_function_call_no_preload (function, thisp, n_args, args, return_value);
162 if (frame == NULL)
163 return;
164 if (thisp != NULL) {
165 swfdec_as_super_new (frame, thisp, thisp->prototype);
166 } else {
167 SWFDEC_FIXME ("does the super object really reference the function when thisp is NULL?");
168 swfdec_as_super_new (frame, SWFDEC_AS_OBJECT (function), SWFDEC_AS_OBJECT (function)->prototype);
170 swfdec_as_frame_preload (frame);
173 /*** AS CODE ***/
175 SWFDEC_AS_NATIVE (101, 10, swfdec_as_function_do_call)
176 void
177 swfdec_as_function_do_call (SwfdecAsContext *cx, SwfdecAsObject *object,
178 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
180 SwfdecAsFunction *fun;
181 SwfdecAsObject *thisp;
183 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_FUNCTION, &fun, "|O", &thisp);
185 if (thisp == NULL) {
186 thisp = swfdec_as_object_new_empty (cx);
187 if (thisp == NULL)
188 return;
190 if (argc > 0) {
191 argc--;
192 argv++;
194 swfdec_as_function_call (fun, thisp, argc, argv, ret);
195 swfdec_as_context_run (cx);
198 SWFDEC_AS_NATIVE (101, 11, swfdec_as_function_apply)
199 void
200 swfdec_as_function_apply (SwfdecAsContext *cx, SwfdecAsObject *object,
201 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
203 SwfdecAsValue *argv_pass = NULL;
204 int length = 0;
205 SwfdecAsFunction *fun;
206 SwfdecAsObject *thisp;
208 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_FUNCTION, &fun, "|O", &thisp);
210 if (thisp == NULL) {
211 thisp = swfdec_as_object_new_empty (cx);
212 if (thisp == NULL)
213 return;
216 if (argc > 1 && SWFDEC_AS_VALUE_IS_OBJECT (&argv[1])) {
217 int i;
218 SwfdecAsObject *array;
219 SwfdecAsValue val;
221 array = SWFDEC_AS_VALUE_GET_OBJECT (&argv[1]);
223 swfdec_as_object_get_variable (array, SWFDEC_AS_STR_length, &val);
224 length = swfdec_as_value_to_integer (cx, &val);
226 if (length > 0) {
227 /* FIXME: find a smarter way to do this, like providing argv not as an array */
228 if (!swfdec_as_context_use_mem (cx, sizeof (SwfdecAsValue) * length))
229 return;
230 argv_pass = g_malloc (sizeof (SwfdecAsValue) * length);
232 for (i = 0; i < length; i++) {
233 swfdec_as_object_get_variable (array,
234 swfdec_as_double_to_string (cx, i), &argv_pass[i]);
236 } else {
237 length = 0;
241 swfdec_as_function_call (fun, thisp, length, argv_pass, ret);
242 swfdec_as_context_run (cx);
244 if (argv_pass) {
245 swfdec_as_context_unuse_mem (cx, sizeof (SwfdecAsValue) * length);
246 g_free (argv_pass);
250 void
251 swfdec_as_function_init_context (SwfdecAsContext *context, guint version)
253 SwfdecAsObject *function, *proto;
254 SwfdecAsValue val;
256 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
258 function = SWFDEC_AS_OBJECT (swfdec_as_object_add_function (context->global,
259 SWFDEC_AS_STR_Function, 0, NULL, 0));
260 if (!function)
261 return;
262 if (version < 6) {
263 /* deleting it later on is easier than duplicating swfdec_as_object_add_function() */
264 swfdec_as_object_unset_variable_flags (context->global, SWFDEC_AS_STR_Function, SWFDEC_AS_VARIABLE_PERMANENT);
265 swfdec_as_object_delete_variable (context->global, SWFDEC_AS_STR_Function);
267 context->Function = function;
268 SWFDEC_AS_VALUE_SET_OBJECT (&val, function);
269 swfdec_as_object_set_variable_and_flags (function, SWFDEC_AS_STR_constructor,
270 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
271 proto = swfdec_as_object_new_empty (context);
272 if (!proto)
273 return;
274 context->Function_prototype = proto;
275 SWFDEC_AS_VALUE_SET_OBJECT (&val, proto);
276 swfdec_as_object_set_variable_and_flags (function, SWFDEC_AS_STR_prototype,
277 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
278 swfdec_as_object_set_variable_and_flags (function, SWFDEC_AS_STR___proto__,
279 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT |
280 SWFDEC_AS_VARIABLE_VERSION_6_UP);
281 SWFDEC_AS_VALUE_SET_OBJECT (&val, function);
282 swfdec_as_object_set_variable_and_flags (proto, SWFDEC_AS_STR_constructor,
283 &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
287 * swfdec_as_function_set_security:
288 * @fun: a #SwfdecFunction
289 * @sec: the security guarding calls to this function
291 * Sets the security object guarding execution of this function. This function
292 * may only be called once per #SwfdecAsFunction.
294 void
295 swfdec_as_function_set_security (SwfdecAsFunction *fun, SwfdecSecurity *sec)
297 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (fun));
298 g_return_if_fail (SWFDEC_IS_SECURITY (sec));
299 g_return_if_fail (fun->priv == NULL);
301 fun->priv = g_object_ref (sec);