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.
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
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
)
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().
56 * This is the base executable object in Swfdec. It is an abstract object. If
57 * you want to create functions yourself, use #SwfdecAsNativeFunction.
61 swfdec_as_function_class_init (SwfdecAsFunctionClass
*klass
)
66 swfdec_as_function_init (SwfdecAsFunction
*function
)
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.
78 swfdec_as_function_set_constructor (SwfdecAsFunction
*fun
)
80 SwfdecAsContext
*context
;
81 SwfdecAsObject
*object
;
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
)
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
);
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... */
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 */
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
;
133 frame
->return_value
= return_value
;
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
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.
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
);
165 swfdec_as_super_new (frame
, thisp
, thisp
->prototype
);
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
);
175 SWFDEC_AS_NATIVE (101, 10, swfdec_as_function_do_call
)
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
);
186 thisp
= swfdec_as_object_new_empty (cx
);
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
)
200 swfdec_as_function_apply (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
201 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*ret
)
203 SwfdecAsValue
*argv_pass
= NULL
;
205 SwfdecAsFunction
*fun
;
206 SwfdecAsObject
*thisp
;
208 SWFDEC_AS_CHECK (SWFDEC_TYPE_AS_FUNCTION
, &fun
, "|O", &thisp
);
211 thisp
= swfdec_as_object_new_empty (cx
);
216 if (argc
> 1 && SWFDEC_AS_VALUE_IS_OBJECT (&argv
[1])) {
218 SwfdecAsObject
*array
;
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
);
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
))
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
]);
241 swfdec_as_function_call (fun
, thisp
, length
, argv_pass
, ret
);
242 swfdec_as_context_run (cx
);
245 swfdec_as_context_unuse_mem (cx
, sizeof (SwfdecAsValue
) * length
);
251 swfdec_as_function_init_context (SwfdecAsContext
*context
, guint version
)
253 SwfdecAsObject
*function
, *proto
;
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));
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
);
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.
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
);