2 * Copyright (C) 2007-2008 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_native_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_strings.h"
30 #include "swfdec_debug.h"
36 * @context: #SwfdecAsContext
37 * @thisp: the this object. <warning>Can be %NULL.</warning>
38 * @argc: number of arguments passed to this function
39 * @argv: the @argc arguments passed to this function
40 * @retval: set to the return value. Initialized to undefined by default
42 * This is the prototype for all native functions.
46 * SwfdecAsNativeFunction:
48 * This is the object type for native functions.
51 /*** IMPLEMENTATION ***/
53 G_DEFINE_TYPE (SwfdecAsNativeFunction
, swfdec_as_native_function
, SWFDEC_TYPE_AS_FUNCTION
)
56 swfdec_as_native_function_call (SwfdecAsFunction
*function
, SwfdecAsObject
*thisp
,
57 gboolean construct
, SwfdecAsObject
*super_reference
, guint n_args
,
58 const SwfdecAsValue
*args
, SwfdecAsValue
*return_value
)
60 SwfdecAsNativeFunction
*native
= SWFDEC_AS_NATIVE_FUNCTION (function
);
61 SwfdecAsContext
*cx
= swfdec_gc_object_get_context (function
);
62 SwfdecAsFrame frame
= { NULL
, };
63 SwfdecAsValue rval
= { 0, };
66 g_assert (native
->name
);
68 swfdec_as_frame_init_native (&frame
, cx
);
69 frame
.construct
= construct
;
70 frame
.function
= function
;
71 /* We copy the target here so we have a proper SwfdecMovie reference inside native
72 * functions. This is for example necessary for swfdec_player_get_movie_by_value()
73 * and probably other stuff that does variable lookups inside native functions.
75 /* FIXME: copy target or original target? */
77 frame
.target
= frame
.next
->original_target
;
78 frame
.original_target
= frame
.target
;
81 thisp
= swfdec_as_object_resolve (thisp
);
82 swfdec_as_frame_set_this (&frame
, thisp
);
86 frame
.return_value
= return_value
;
87 frame
.construct
= construct
;
89 if (frame
.argc
== 0 || frame
.argv
!= NULL
) {
90 /* FIXME FIXME FIXME: no casting here please! */
91 argv
= (SwfdecAsValue
*) frame
.argv
;
96 if (frame
.argc
> 128) {
97 SWFDEC_FIXME ("allow calling native functions with more than 128 args (this one has %u)",
101 argv
= g_new (SwfdecAsValue
, frame
.argc
);
104 for (i
= 0; i
< frame
.argc
; i
++) {
105 if (cur
<= &stack
->elements
[0]) {
107 cur
= &stack
->elements
[stack
->used_elements
];
113 native
->native (cx
, thisp
, frame
.argc
, argv
, &rval
);
114 if (argv
!= frame
.argv
)
116 swfdec_as_context_return (cx
, &rval
);
120 swfdec_as_native_function_dispose (GObject
*object
)
122 SwfdecAsNativeFunction
*function
= SWFDEC_AS_NATIVE_FUNCTION (object
);
124 g_free (function
->name
);
125 function
->name
= NULL
;
127 G_OBJECT_CLASS (swfdec_as_native_function_parent_class
)->dispose (object
);
131 swfdec_as_native_function_class_init (SwfdecAsNativeFunctionClass
*klass
)
133 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
134 SwfdecAsFunctionClass
*function_class
= SWFDEC_AS_FUNCTION_CLASS (klass
);
136 object_class
->dispose
= swfdec_as_native_function_dispose
;
138 function_class
->call
= swfdec_as_native_function_call
;
142 swfdec_as_native_function_init (SwfdecAsNativeFunction
*function
)
147 * swfdec_as_native_function_new:
148 * @context: a #SwfdecAsContext
149 * @name: name of the function
150 * @native: function to call when executed
152 * Creates a new native function, that will execute @native when called. You
153 * might want to use swfdec_as_object_add_function() instead of this function.
155 * Returns: a new #SwfdecAsFunction
158 swfdec_as_native_function_new (SwfdecAsContext
*context
, const char *name
,
159 SwfdecAsNative native
)
161 SwfdecAsFunction
*fun
;
162 SwfdecAsObject
*object
;
164 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
165 g_return_val_if_fail (native
!= NULL
, NULL
);
167 fun
= swfdec_as_native_function_new_bare (context
, name
, native
);
168 object
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (fun
));
170 swfdec_as_object_set_constructor_by_name (object
, SWFDEC_AS_STR_Function
, NULL
);
171 swfdec_as_object_set_variable_flags (object
, SWFDEC_AS_STR___proto__
, SWFDEC_AS_VARIABLE_VERSION_6_UP
);
177 swfdec_as_native_function_new_bare (SwfdecAsContext
*context
, const char *name
,
178 SwfdecAsNative native
)
180 SwfdecAsNativeFunction
*fun
;
181 SwfdecAsObject
*object
;
183 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
184 g_return_val_if_fail (native
!= NULL
, NULL
);
186 fun
= g_object_new (SWFDEC_TYPE_AS_NATIVE_FUNCTION
, "context", context
, NULL
);
187 fun
->native
= native
;
188 fun
->name
= g_strdup (name
);
190 object
= swfdec_as_object_new_empty (context
);
191 swfdec_as_object_set_relay (object
, SWFDEC_AS_RELAY (fun
));
193 return SWFDEC_AS_FUNCTION (fun
);
198 * @type: required type of this object or 0 for ignoring
199 * @result: converted this object
200 * @...: conversion string and pointers taking converted values
202 * This is a shortcut macro for calling swfdec_as_native_function_check() at
203 * the beginning of a native function. See that function for details.
204 * It requires the native function parameters to have the default name. So your
205 * function must be declared like this:
207 * my_function (SwfdecAsContext *cx, SwfdecAsObject *object,
208 * guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval);]|
211 * swfdec_as_native_function_check:
212 * @cx: a #SwfdecAsContext
213 * @object: this object passed to the native function
214 * @type: expected type of @object or 0 for any
215 * @result: pointer to variable taking cast result of @object
216 * @argc: count of arguments passed to the function
217 * @argv: arguments passed to the function
218 * @args: argument conversion string
219 * @...: pointers to variables taking converted arguments
221 * This function is a convenience function to validate and convert arguments to
222 * a native function while avoiding common pitfalls. You typically want to call
223 * it at the beginning of every native function you write. Or you can use the
224 * SWFDEC_AS_CHECK() macro instead which calls this function.
225 * The @cx, @object, @argc and @argv paramters should be passed verbatim from
226 * the function call to your native function. If @type is not 0, @object is then
227 * checked to be of that type and cast to @result. After that the @args string
228 * is used to convert the arguments. Every character in @args describes the
229 * conversion of one argument. For that argument, you have to pass a pointer
230 * that takes the value. For the conversion, the default conversion functions
231 * like swfdec_as_value_to_string() are used. If not enough arguments are
232 * available, the function stops converting and returns %NULL. The following
233 * conversion characters are allowed:<itemizedlist>
234 * <listitem><para>"b": convert to boolean. Requires a %gboolean pointer
236 * <listitem><para>"i": convert to integer. Requires an %integer pointer
238 * <listitem><para>"m": convert to an existing movieclip. This is only valid
239 * inside Swfdec. Requires a %SwfdecMovie pointer.
241 * <listitem><para>"M": convert to a movieclip or %NULL. This is only valid
242 * inside Swfdec. If the movie has already been destroyed,
243 * the pointer will be set to %NULL</para></listitem>
244 * <listitem><para>"n": convert to number. Requires a %double pointer
246 * <listitem><para>"o": convert to object. Requires a #SwfdecAsObject pointer.
247 * If the conversion fails, this function immediately returns
248 * %FALSE.</para></listitem>
249 * <listitem><para>"O": convert to object or %NULL. Requires a #SwfdecAsObject
250 * pointer.</para></listitem>
251 * <listitem><para>"s": convert to garbage-collected string. Requires a const
252 * %char pointer</para></listitem>
253 * <listitem><para>"v": copy the value. The given argument must be a pointer
254 * to a #SwfdecAsValue</para></listitem>
255 * <listitem><para>"|": optional arguments follow. Optional arguments will be
256 * initialized to the empty value for their type. This
257 * conversion character is only allowed once in the conversion
258 * string.</para></listitem>
261 * Returns: %TRUE if the conversion succeeded, %FALSE otherwise
264 swfdec_as_native_function_check (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
265 GType type
, gpointer
*result
, guint argc
, SwfdecAsValue
*argv
,
266 const char *args
, ...)
271 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx
), FALSE
);
272 g_return_val_if_fail (type
== 0 || result
!= NULL
, FALSE
);
274 va_start (varargs
, args
);
275 ret
= swfdec_as_native_function_checkv (cx
, object
, type
, result
, argc
, argv
, args
, varargs
);
281 * swfdec_as_native_function_checkv:
282 * @cx: a #SwfdecAsContext
283 * @object: this object passed to the native function
284 * @type: expected type of @object
285 * @result: pointer to variable taking cast result of @object
286 * @argc: count of arguments passed to the function
287 * @argv: arguments passed to the function
288 * @args: argument conversion string
289 * @varargs: pointers to variables taking converted arguments
291 * This is the valist version of swfdec_as_native_function_check(). See that
292 * function for details.
294 * Returns: %TRUE if the conversion succeeded, %FALSE otherwise
297 swfdec_as_native_function_checkv (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
298 GType type
, gpointer
*result
, guint argc
, SwfdecAsValue
*argv
,
299 const char *args
, va_list varargs
)
302 gboolean optional
= FALSE
;
304 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx
), FALSE
);
305 g_return_val_if_fail (type
== 0 || result
!= NULL
, FALSE
);
307 /* check that we got a valid type */
309 if (G_TYPE_CHECK_INSTANCE_TYPE (object
, type
)) {
311 } else if (object
&& G_TYPE_CHECK_INSTANCE_TYPE (object
->relay
, type
)) {
312 *result
= object
->relay
;
317 for (i
= 0; *args
&& i
< argc
; i
++, args
++) {
321 SwfdecAsValue
*val
= va_arg (varargs
, SwfdecAsValue
*);
327 gboolean
*b
= va_arg (varargs
, gboolean
*);
328 *b
= swfdec_as_value_to_boolean (cx
, argv
[i
]);
333 int *j
= va_arg (varargs
, int *);
334 *j
= swfdec_as_value_to_integer (cx
, argv
[i
]);
341 SwfdecMovie
**arg
= va_arg (varargs
, SwfdecMovie
**);
342 if (SWFDEC_AS_VALUE_IS_MOVIE (argv
[i
])) {
343 m
= SWFDEC_AS_VALUE_GET_MOVIE (argv
[i
]);
347 if (m
== NULL
&& *args
!= 'M')
354 double *d
= va_arg (varargs
, double *);
355 *d
= swfdec_as_value_to_number (cx
, argv
[i
]);
360 const char **s
= va_arg (varargs
, const char **);
361 *s
= swfdec_as_value_to_string (cx
, argv
[i
]);
367 SwfdecAsObject
**o
= va_arg (varargs
, SwfdecAsObject
**);
368 *o
= swfdec_as_value_to_object (cx
, argv
[i
]);
369 if (*o
== NULL
&& *args
!= 'O')
374 g_return_val_if_fail (optional
== FALSE
, FALSE
);
379 g_warning ("'%c' is not a valid type conversion", *args
);
383 if (*args
&& !optional
&& *args
!= '|')