fix build for --disable-gtk-doc
[swfdec.git] / swfdec / swfdec_as_native_function.c
blobe827066b4b09ffbf95b73cf4b2faee8e7ffafab0
1 /* Swfdec
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.
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_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"
32 /*** GTK-DOC ***/
34 /**
35 * SwfdecAsNative:
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.
45 /**
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)
55 static void
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, };
64 SwfdecAsValue *argv;
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? */
76 if (frame.next) {
77 frame.target = frame.next->original_target;
78 frame.original_target = frame.target;
80 if (thisp) {
81 thisp = swfdec_as_object_resolve (thisp);
82 swfdec_as_frame_set_this (&frame, thisp);
84 frame.argc = n_args;
85 frame.argv = args;
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;
92 } else {
93 SwfdecAsStack *stack;
94 SwfdecAsValue *cur;
95 guint i;
96 if (frame.argc > 128) {
97 SWFDEC_FIXME ("allow calling native functions with more than 128 args (this one has %u)",
98 frame.argc);
99 frame.argc = 128;
101 argv = g_new (SwfdecAsValue, frame.argc);
102 stack = cx->stack;
103 cur = cx->cur;
104 for (i = 0; i < frame.argc; i++) {
105 if (cur <= &stack->elements[0]) {
106 stack = stack->next;
107 cur = &stack->elements[stack->used_elements];
109 cur--;
110 argv[i] = *cur;
113 native->native (cx, thisp, frame.argc, argv, &rval);
114 if (argv != frame.argv)
115 g_free (argv);
116 swfdec_as_context_return (cx, &rval);
119 static void
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);
130 static void
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;
141 static void
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
157 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);
173 return fun;
176 SwfdecAsFunction *
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);
197 * SWFDEC_AS_CHECK:
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:
206 * |[static void
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
235 * </para></listitem>
236 * <listitem><para>"i": convert to integer. Requires an %integer pointer
237 * </para></listitem>
238 * <listitem><para>"m": convert to an existing movieclip. This is only valid
239 * inside Swfdec. Requires a %SwfdecMovie pointer.
240 * </para></listitem>
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
245 * </para></listitem>
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>
259 * </itemizedlist>
261 * Returns: %TRUE if the conversion succeeded, %FALSE otherwise
263 gboolean
264 swfdec_as_native_function_check (SwfdecAsContext *cx, SwfdecAsObject *object,
265 GType type, gpointer *result, guint argc, SwfdecAsValue *argv,
266 const char *args, ...)
268 gboolean ret;
269 va_list varargs;
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);
276 va_end (varargs);
277 return ret;
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
296 gboolean
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)
301 guint i;
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 */
308 if (type) {
309 if (G_TYPE_CHECK_INSTANCE_TYPE (object, type)) {
310 *result = object;
311 } else if (object && G_TYPE_CHECK_INSTANCE_TYPE (object->relay, type)) {
312 *result = object->relay;
313 } else {
314 return FALSE;
317 for (i = 0; *args && i < argc; i++, args++) {
318 switch (*args) {
319 case 'v':
321 SwfdecAsValue *val = va_arg (varargs, SwfdecAsValue *);
322 *val = argv[i];
324 break;
325 case 'b':
327 gboolean *b = va_arg (varargs, gboolean *);
328 *b = swfdec_as_value_to_boolean (cx, argv[i]);
330 break;
331 case 'i':
333 int *j = va_arg (varargs, int *);
334 *j = swfdec_as_value_to_integer (cx, argv[i]);
336 break;
337 case 'm':
338 case 'M':
340 SwfdecMovie *m;
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]);
344 } else {
345 m = NULL;
347 if (m == NULL && *args != 'M')
348 return FALSE;
349 *arg = m;
351 break;
352 case 'n':
354 double *d = va_arg (varargs, double *);
355 *d = swfdec_as_value_to_number (cx, argv[i]);
357 break;
358 case 's':
360 const char **s = va_arg (varargs, const char **);
361 *s = swfdec_as_value_to_string (cx, argv[i]);
363 break;
364 case 'o':
365 case 'O':
367 SwfdecAsObject **o = va_arg (varargs, SwfdecAsObject **);
368 *o = swfdec_as_value_to_object (cx, argv[i]);
369 if (*o == NULL && *args != 'O')
370 return FALSE;
372 break;
373 case '|':
374 g_return_val_if_fail (optional == FALSE, FALSE);
375 optional = TRUE;
376 i--;
377 break;
378 default:
379 g_warning ("'%c' is not a valid type conversion", *args);
380 return FALSE;
383 if (*args && !optional && *args != '|')
384 return FALSE;
385 return TRUE;