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
26 #include "swfdec_as_object.h"
27 #include "swfdec_as_context.h"
28 #include "swfdec_as_frame_internal.h"
29 #include "swfdec_as_internal.h"
30 #include "swfdec_as_native_function.h"
31 #include "swfdec_as_stack.h"
32 #include "swfdec_as_string.h"
33 #include "swfdec_as_strings.h"
34 #include "swfdec_debug.h"
35 #include "swfdec_movie.h"
37 #define SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT 256
40 * SECTION:SwfdecAsObject
41 * @title: SwfdecAsObject
42 * @short_description: the base object type for scriptable objects
44 * This is the basic object type in Swfdec. Every object used by the script
45 * engine must be a #SwfdecAsObject. It handles memory management and assigning
46 * variables to it. Almost all functions that are called on objects require that
47 * the objects have been added to the garbage collector previously. For
48 * custom-created objects, you need to do this using swfdec_as_object_add(),
49 * built-in functions that create objects do this manually.
51 * Note that you cannot know the lifetime of a #SwfdecAsObject, since scripts
52 * may assign it as a variable to other objects. So you should not assume to
53 * know when an object gets removed.
59 * Every object value inside the Swfdec script engine must be a SwfdecAsObject.
60 * If you want to add custom objects to your script engine, you need to create a
61 * subclass. The class provides a number of virtual functions that you can
62 * override to achieve the desired behaviour.
66 * SwfdecAsVariableFlag:
67 * @SWFDEC_AS_VARIABLE_HIDDEN: Do not include variable in enumerations and
68 * swfdec_as_object_foreach().
69 * @SWFDEC_AS_VARIABLE_PERMANENT: Do not all swfdec_as_object_delete_variable()
70 * to delete this variable.
71 * @SWFDEC_AS_VARIABLE_CONSTANT: Do not allow changing the value with
72 * swfdec_as_object_set_variable().
73 * @SWFDEC_AS_VARIABLE_VERSION_6_UP: This symbol is only visible in version 6
75 * @SWFDEC_AS_VARIABLE_VERSION_NOT_6: This symbols is visible in all versions
77 * @SWFDEC_AS_VARIABLE_VERSION_7_UP: This symbol is only visible in version 7
79 * @SWFDEC_AS_VARIABLE_VERSION_8_UP: This symbol is only visible in version 8
82 * These flags are used to describe various properties of a variable inside
83 * Swfdec. You can manually set them with swfdec_as_object_set_variable_flags().
87 * SwfdecAsDeleteReturn:
88 * @SWFDEC_AS_DELETE_NOT_FOUND: The variable was not found and therefore
89 * couldn't be deleted.
90 * @SWFDEC_AS_DELETE_DELETED: The variable was deleted.
91 * @SWFDEC_AS_DELETE_NOT_DELETED: The variable was found but could not be
94 * This is the return value used by swfdec_as_object_delete_variable(). It
95 * describes the various outcomes of trying to delete a variable.
99 * SwfdecAsVariableForeach:
100 * @object: The object this function is run on
101 * @variable: garbage-collected name of the current variables
102 * @value: value of the current variable
103 * @flags: Flags associated with the current variable
104 * @data: User dta passed to swfdec_as_object_foreach()
106 * Function prototype for the swfdec_as_object_foreach() function.
108 * Returns: %TRUE to continue running the foreach function, %FALSE to stop
111 typedef struct _SwfdecAsVariable SwfdecAsVariable
;
112 struct _SwfdecAsVariable
{
113 guint flags
; /* SwfdecAsVariableFlag values */
114 SwfdecAsValue value
; /* value of property */
115 SwfdecAsFunction
* get
; /* getter set with swfdec_as_object_add_property */
116 SwfdecAsFunction
* set
; /* setter or %NULL */
120 SwfdecAsFunction
* watch
; /* watcher or %NULL */
121 SwfdecAsValue watch_data
; /* user data to watcher */
122 guint refcount
; /* refcount - misused for recursion detection */
125 G_DEFINE_TYPE (SwfdecAsObject
, swfdec_as_object
, G_TYPE_OBJECT
)
128 swfdec_as_object_dispose (GObject
*gobject
)
130 SwfdecAsObject
*object
= SWFDEC_AS_OBJECT (gobject
);
132 g_assert (object
->properties
== NULL
);
134 G_OBJECT_CLASS (swfdec_as_object_parent_class
)->dispose (gobject
);
138 swfdec_as_object_mark_property (gpointer key
, gpointer value
, gpointer unused
)
140 SwfdecAsVariable
*var
= value
;
142 swfdec_as_string_mark (key
);
144 swfdec_as_object_mark (SWFDEC_AS_OBJECT (var
->get
));
146 swfdec_as_object_mark (SWFDEC_AS_OBJECT (var
->set
));
148 swfdec_as_value_mark (&var
->value
);
153 swfdec_as_object_mark_watch (gpointer key
, gpointer value
, gpointer unused
)
155 SwfdecAsWatch
*watch
= value
;
157 swfdec_as_string_mark (key
);
158 swfdec_as_object_mark (SWFDEC_AS_OBJECT (watch
->watch
));
159 swfdec_as_value_mark (&watch
->watch_data
);
163 swfdec_as_object_do_mark (SwfdecAsObject
*object
)
165 if (object
->prototype
)
166 swfdec_as_object_mark (object
->prototype
);
167 g_hash_table_foreach (object
->properties
, swfdec_as_object_mark_property
, NULL
);
169 g_hash_table_foreach (object
->watches
, swfdec_as_object_mark_watch
, NULL
);
173 swfdec_as_object_do_add (SwfdecAsObject
*object
)
178 swfdec_as_object_lookup_case_insensitive (gpointer key
, gpointer value
, gpointer user_data
)
180 return g_ascii_strcasecmp (key
, user_data
) == 0;
184 swfdec_as_variable_name_is_valid (const char *name
)
186 return name
!= SWFDEC_AS_STR_EMPTY
;
189 static inline SwfdecAsVariable
*
190 swfdec_as_object_hash_lookup (SwfdecAsObject
*object
, const char *variable
)
192 SwfdecAsVariable
*var
= g_hash_table_lookup (object
->properties
, variable
);
194 if (var
|| object
->context
->version
>= 7)
196 var
= g_hash_table_find (object
->properties
, swfdec_as_object_lookup_case_insensitive
, (gpointer
) variable
);
200 static inline SwfdecAsVariable
*
201 swfdec_as_object_hash_create (SwfdecAsObject
*object
, const char *variable
, guint flags
)
203 SwfdecAsVariable
*var
;
205 if (!swfdec_as_context_use_mem (object
->context
, sizeof (SwfdecAsVariable
)))
207 if (!swfdec_as_variable_name_is_valid (variable
))
209 var
= g_slice_new0 (SwfdecAsVariable
);
211 g_hash_table_insert (object
->properties
, (gpointer
) variable
, var
);
217 swfdec_as_object_do_get (SwfdecAsObject
*object
, SwfdecAsObject
*orig
,
218 const char *variable
, SwfdecAsValue
*val
, guint
*flags
)
220 SwfdecAsVariable
*var
= swfdec_as_object_hash_lookup (object
, variable
);
225 /* variable flag checks */
226 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_6_UP
&& object
->context
->version
< 6)
228 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_NOT_6
&& object
->context
->version
== 6)
230 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_7_UP
&& object
->context
->version
< 7)
232 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_8_UP
&& object
->context
->version
< 8)
236 swfdec_as_function_call (var
->get
, orig
, 0, NULL
, val
);
237 swfdec_as_context_run (object
->context
);
246 static SwfdecAsWatch
*
247 swfdec_as_watch_new (SwfdecAsFunction
*function
)
249 SwfdecAsWatch
*watch
;
251 if (!swfdec_as_context_use_mem (SWFDEC_AS_OBJECT (function
)->context
,
252 sizeof (SwfdecAsWatch
)))
255 watch
= g_slice_new (SwfdecAsWatch
);
257 watch
->watch
= function
;
258 SWFDEC_AS_VALUE_SET_UNDEFINED (&watch
->watch_data
);
262 static inline gboolean
263 swfdec_as_watch_can_recurse (SwfdecAsWatch
*watch
)
267 version
= SWFDEC_AS_OBJECT (watch
->watch
)->context
->version
;
269 return watch
->refcount
<= 1;
271 return watch
->refcount
<= 64 + 1;
276 swfdec_as_watch_ref (SwfdecAsWatch
*watch
)
282 swfdec_as_watch_unref (SwfdecAsWatch
*watch
)
285 if (watch
->refcount
== 0) {
286 swfdec_as_context_unuse_mem (SWFDEC_AS_OBJECT (watch
->watch
)->context
,
287 sizeof (SwfdecAsWatch
));
288 g_slice_free (SwfdecAsWatch
, watch
);
293 swfdec_as_object_prototype_for_version (SwfdecAsObject
*object
, guint version
,
296 if (object
->prototype
== NULL
)
299 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_6_UP
&& version
< 6)
301 // don't check for NOT_6 flag
302 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_7_UP
&& version
< 7)
304 // only check 8_UP for version < 6
305 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_8_UP
&&
309 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_8_UP
&& version
== 7)
313 return object
->prototype
;
317 swfdec_as_object_do_set (SwfdecAsObject
*object
, const char *variable
,
318 const SwfdecAsValue
*val
, guint flags
)
320 SwfdecAsVariable
*var
;
321 SwfdecAsWatch
*watch
;
323 if (!swfdec_as_variable_name_is_valid (variable
))
326 var
= swfdec_as_object_hash_lookup (object
, variable
);
327 if (var
== NULL
&& variable
!= SWFDEC_AS_STR___proto__
) {
329 SwfdecAsObject
*proto
;
331 proto
= swfdec_as_object_prototype_for_version (object
,
332 object
->context
->version
, FALSE
);
334 for (i
= 0; i
< SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
&& proto
; i
++) {
335 var
= swfdec_as_object_hash_lookup (proto
, variable
);
338 proto
= swfdec_as_object_prototype_for_version (proto
,
339 proto
->context
->version
, FALSE
);
342 if (i
== SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
) {
343 swfdec_as_context_abort (object
->context
, "Prototype recursion limit exceeded");
348 var
= swfdec_as_object_hash_create (object
, variable
, flags
);
352 if (var
->flags
& SWFDEC_AS_VARIABLE_CONSTANT
)
354 // remove the flags that could make this variable hidden
355 if (object
->context
->version
== 6) {
356 // version 6, so let's forget SWFDEC_AS_VARIABLE_VERSION_7_UP flag, oops!
357 // we will still set the value though, even if that flag is set
358 var
->flags
&= ~(SWFDEC_AS_VARIABLE_VERSION_6_UP
|
359 SWFDEC_AS_VARIABLE_VERSION_NOT_6
| SWFDEC_AS_VARIABLE_VERSION_8_UP
);
361 var
->flags
&= ~(SWFDEC_AS_VARIABLE_VERSION_6_UP
|
362 SWFDEC_AS_VARIABLE_VERSION_NOT_6
| SWFDEC_AS_VARIABLE_VERSION_7_UP
|
363 SWFDEC_AS_VARIABLE_VERSION_8_UP
);
366 if (object
->watches
) {
367 SwfdecAsValue ret
= *val
;
368 watch
= g_hash_table_lookup (object
->watches
, variable
);
369 /* FIXME: figure out if this limit here is correct. Add a watch in Flash 7
370 * and set a variable using Flash 6 */
371 if (watch
&& swfdec_as_watch_can_recurse (watch
)) {
372 SwfdecAsValue args
[4];
373 SWFDEC_AS_VALUE_SET_STRING (&args
[0], variable
);
374 args
[1] = var
->value
;
376 args
[3] = watch
->watch_data
;
377 swfdec_as_watch_ref (watch
);
378 swfdec_as_function_call (watch
->watch
, object
, 4, args
, &ret
);
379 swfdec_as_context_run (object
->context
);
380 swfdec_as_watch_unref (watch
);
381 var
= swfdec_as_object_hash_lookup (object
, variable
);
393 swfdec_as_function_call (var
->set
, object
, 1, val
, &tmp
);
394 swfdec_as_context_run (object
->context
);
396 } else if (watch
== NULL
) {
400 if (variable
== SWFDEC_AS_STR___proto__
) {
401 if (SWFDEC_AS_VALUE_IS_OBJECT (val
) &&
402 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (val
))) {
403 object
->prototype
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
404 object
->prototype_flags
= var
->flags
;
406 object
->prototype
= NULL
;
407 object
->prototype_flags
= 0;
413 swfdec_as_object_do_set_flags (SwfdecAsObject
*object
, const char *variable
, guint flags
, guint mask
)
415 SwfdecAsVariable
*var
= swfdec_as_object_hash_lookup (object
, variable
);
418 var
->flags
= (var
->flags
& ~mask
) | flags
;
420 if (variable
== SWFDEC_AS_STR___proto__
)
421 object
->prototype_flags
= var
->flags
;
426 swfdec_as_object_free_property (gpointer key
, gpointer value
, gpointer data
)
428 SwfdecAsObject
*object
= data
;
430 swfdec_as_context_unuse_mem (object
->context
, sizeof (SwfdecAsVariable
));
431 g_slice_free (SwfdecAsVariable
, value
);
434 static SwfdecAsDeleteReturn
435 swfdec_as_object_do_delete (SwfdecAsObject
*object
, const char *variable
)
437 SwfdecAsVariable
*var
;
439 var
= g_hash_table_lookup (object
->properties
, variable
);
441 return SWFDEC_AS_DELETE_NOT_FOUND
;
442 if (var
->flags
& SWFDEC_AS_VARIABLE_PERMANENT
)
443 return SWFDEC_AS_DELETE_NOT_DELETED
;
445 if (variable
== SWFDEC_AS_STR___proto__
&& object
->context
->version
<= 6) {
446 object
->prototype
= NULL
;
447 object
->prototype_flags
= 0;
449 swfdec_as_object_free_property (NULL
, var
, object
);
450 if (!g_hash_table_remove (object
->properties
, variable
)) {
451 g_assert_not_reached ();
453 return SWFDEC_AS_DELETE_DELETED
;
457 SwfdecAsObject
* object
;
458 SwfdecAsVariableForeach func
;
464 swfdec_as_object_hash_foreach (gpointer key
, gpointer value
, gpointer data
)
466 ForeachData
*fdata
= data
;
467 SwfdecAsVariable
*var
= value
;
472 fdata
->retval
= fdata
->func (fdata
->object
, key
, &var
->value
, var
->flags
, fdata
->data
);
475 /* FIXME: does not do Adobe Flash's order for Enumerate actions */
477 swfdec_as_object_do_foreach (SwfdecAsObject
*object
, SwfdecAsVariableForeach func
, gpointer data
)
479 ForeachData fdata
= { object
, func
, data
, TRUE
};
481 g_hash_table_foreach (object
->properties
, swfdec_as_object_hash_foreach
, &fdata
);
486 SwfdecAsObject
* object
;
487 SwfdecAsVariableForeachRemove func
;
492 swfdec_as_object_hash_foreach_remove (gpointer key
, gpointer value
, gpointer data
)
494 ForeachRemoveData
*fdata
= data
;
495 SwfdecAsVariable
*var
= value
;
497 if (!fdata
->func (fdata
->object
, key
, &var
->value
, var
->flags
, fdata
->data
))
500 swfdec_as_object_free_property (NULL
, var
, fdata
->object
);
505 * swfdec_as_object_foreach_remove:
506 * @object: a #SwfdecAsObject
507 * @func: function that determines which object to remove
508 * @data: data to pass to @func
510 * Removes all variables form @object where @func returns %TRUE. This is an
511 * internal function for array operations.
513 * Returns: he number of variables removed
516 swfdec_as_object_foreach_remove (SwfdecAsObject
*object
, SwfdecAsVariableForeach func
,
519 ForeachRemoveData fdata
= { object
, func
, data
};
521 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), 0);
522 g_return_val_if_fail (func
!= NULL
, 0);
524 return g_hash_table_foreach_remove (object
->properties
,
525 swfdec_as_object_hash_foreach_remove
, &fdata
);
529 SwfdecAsObject
* object
;
530 GHashTable
* properties_new
;
531 SwfdecAsVariableForeachRename func
;
536 swfdec_as_object_hash_foreach_rename (gpointer key
, gpointer value
, gpointer data
)
538 ForeachRenameData
*fdata
= data
;
539 SwfdecAsVariable
*var
= value
;
542 key_new
= fdata
->func (fdata
->object
, key
, &var
->value
, var
->flags
, fdata
->data
);
544 g_hash_table_insert (fdata
->properties_new
, (gpointer
) key_new
, var
);
546 swfdec_as_object_free_property (NULL
, var
, fdata
->object
);
553 * swfdec_as_object_foreach_rename:
554 * @object: a #SwfdecAsObject
555 * @func: function determining the new name
556 * @data: data to pass to @func
558 * Calls @func for each variable of @object. The function is then supposed
559 * to return the new name of the variable or %NULL if the variable should be
560 * removed. This is an internal function for array operations.
563 swfdec_as_object_foreach_rename (SwfdecAsObject
*object
, SwfdecAsVariableForeachRename func
,
566 ForeachRenameData fdata
= { object
, NULL
, func
, data
};
568 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
569 g_return_if_fail (func
!= NULL
);
571 fdata
.properties_new
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
572 g_hash_table_foreach_remove (object
->properties
, swfdec_as_object_hash_foreach_rename
, &fdata
);
573 g_hash_table_destroy (object
->properties
);
574 object
->properties
= fdata
.properties_new
;
578 swfdec_as_object_do_debug (SwfdecAsObject
*object
)
580 if (G_OBJECT_TYPE (object
) != SWFDEC_TYPE_AS_OBJECT
)
581 return g_strdup (G_OBJECT_TYPE_NAME (object
));
583 return g_strdup ("Object");
587 swfdec_as_object_class_init (SwfdecAsObjectClass
*klass
)
589 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
591 object_class
->dispose
= swfdec_as_object_dispose
;
593 klass
->mark
= swfdec_as_object_do_mark
;
594 klass
->add
= swfdec_as_object_do_add
;
595 klass
->get
= swfdec_as_object_do_get
;
596 klass
->set
= swfdec_as_object_do_set
;
597 klass
->set_flags
= swfdec_as_object_do_set_flags
;
598 klass
->del
= swfdec_as_object_do_delete
;
599 klass
->foreach
= swfdec_as_object_do_foreach
;
600 klass
->debug
= swfdec_as_object_do_debug
;
604 swfdec_as_object_init (SwfdecAsObject
*object
)
609 * swfdec_as_object_new_empty:
610 * @context: a #SwfdecAsContext
612 * Creates an empty object. The prototype and constructor properties of the
613 * returned object will not be set. You probably want to call
614 * swfdec_as_object_set_constructor() on the returned object yourself.
615 * You may want to use swfdec_as_object_new() instead.
617 * Returns: A new #SwfdecAsObject adde to @context or %NULL on OOM.
620 swfdec_as_object_new_empty (SwfdecAsContext
*context
)
622 SwfdecAsObject
*object
;
624 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
626 if (!swfdec_as_context_use_mem (context
, sizeof (SwfdecAsObject
)))
628 object
= g_object_new (SWFDEC_TYPE_AS_OBJECT
, NULL
);
629 swfdec_as_object_add (object
, context
, sizeof (SwfdecAsObject
));
634 * swfdec_as_object_new:
635 * @context: a #SwfdecAsContext
637 * Allocates a new Object. This does the same as the Actionscript code
640 * Returns: the new object or NULL on out of memory.
643 swfdec_as_object_new (SwfdecAsContext
*context
)
645 SwfdecAsObject
*object
;
648 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
649 g_assert (context
->Object
);
650 g_assert (context
->Object_prototype
);
652 object
= swfdec_as_object_new_empty (context
);
653 SWFDEC_AS_VALUE_SET_OBJECT (&val
, context
->Object
);
654 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR_constructor
,
655 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
656 SWFDEC_AS_VALUE_SET_OBJECT (&val
, context
->Object_prototype
);
657 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR___proto__
,
658 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
663 * swfdec_as_object_add:
664 * @object: #SwfdecAsObject to make garbage-collected
665 * @context: #SwfdecAsContext that should manage the object
666 * @size: size the object currently uses
668 * Takes over the reference to @object for the garbage collector of @context.
669 * The object may not already be part of a different context. The given @size
670 * must have been allocated before with swfdec_as_context_use_mem ().
671 * Note that after swfdec_as_object_add() the garbage collector might hold the
672 * only reference to @object.
675 swfdec_as_object_add (SwfdecAsObject
*object
, SwfdecAsContext
*context
, gsize size
)
677 SwfdecAsObjectClass
*klass
;
679 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
680 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context
));
681 g_return_if_fail (object
->properties
== NULL
);
683 object
->context
= context
;
685 g_hash_table_insert (context
->objects
, object
, object
);
686 object
->properties
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
687 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
688 g_return_if_fail (klass
->add
);
690 if (context
->debugger
) {
691 SwfdecAsDebuggerClass
*dklass
= SWFDEC_AS_DEBUGGER_GET_CLASS (context
->debugger
);
693 dklass
->add (context
->debugger
, context
, object
);
697 /* This is a huge hack design-wise, but we can't use watch->watch,
698 * it might be gone already */
700 swfdec_as_object_steal_watches (gpointer key
, gpointer value
, gpointer object
)
702 SwfdecAsWatch
*watch
= value
;
704 g_assert (watch
->refcount
== 1);
705 watch
->watch
= (SwfdecAsFunction
*) object
;
706 swfdec_as_watch_unref (watch
);
711 swfdec_as_object_collect (SwfdecAsObject
*object
)
713 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
714 g_return_if_fail (object
->properties
!= NULL
);
716 g_hash_table_foreach (object
->properties
, swfdec_as_object_free_property
, object
);
717 g_hash_table_destroy (object
->properties
);
718 object
->properties
= NULL
;
719 if (object
->watches
) {
720 g_hash_table_foreach_steal (object
->watches
, swfdec_as_object_steal_watches
, object
);
721 g_hash_table_destroy (object
->watches
);
722 object
->watches
= NULL
;
725 swfdec_as_context_unuse_mem (object
->context
, object
->size
);
726 g_object_unref (object
);
730 * swfdec_as_object_set_variable:
731 * @object: a #SwfdecAsObject
732 * @variable: garbage-collected name of the variable to set
733 * @value: value to set the variable to
735 * Sets a variable on @object. It is not guaranteed that getting the variable
736 * after setting it results in the same value. This is a mcaro that calls
737 * swfdec_as_object_set_variable_and_flags()
740 * swfdec_as_object_set_variable_and_flags:
741 * @object: a #SwfdecAsObject
742 * @variable: garbage-collected name of the variable to set
743 * @value: value to set the variable to
744 * @default_flags: flags to use if creating the variable anew - the flags will
745 * be ignored if the property already exists.
747 * Sets a variable on @object. It is not guaranteed that getting the variable
748 * after setting it results in the same value, because various mechanisms (like
749 * the Actionscript Object.addProperty function or constant variables) can
753 swfdec_as_object_set_variable_and_flags (SwfdecAsObject
*object
,
754 const char *variable
, const SwfdecAsValue
*value
, guint default_flags
)
756 SwfdecAsObjectClass
*klass
;
758 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
759 g_return_if_fail (variable
!= NULL
);
760 g_return_if_fail (SWFDEC_IS_AS_VALUE (value
));
762 if (object
->context
->debugger
) {
763 SwfdecAsDebugger
*debugger
= object
->context
->debugger
;
764 SwfdecAsDebuggerClass
*dklass
= SWFDEC_AS_DEBUGGER_GET_CLASS (debugger
);
765 if (dklass
->set_variable
)
766 dklass
->set_variable (debugger
, object
->context
, object
, variable
, value
);
768 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
769 klass
->set (object
, variable
, value
, default_flags
);
773 * swfdec_as_object_get_variable:
774 * @object: a #SwfdecAsObject
775 * @variable: a garbage-collected string containing the name of the variable
776 * @value: pointer to a #SwfdecAsValue that takes the return value or %NULL
778 * Gets the value of the given @variable on @object. It walks the prototype
779 * chain. This is a shortcut macro for
780 * swfdec_as_object_get_variable_and_flags().
782 * Returns: %TRUE if the variable existed, %FALSE otherwise
786 * swfdec_as_object_get_variable_and_flags:
787 * @object: a #SwfdecAsObject
788 * @variable: a garbage-collected string containing the name of the variable
789 * @value: pointer to a #SwfdecAsValue that takes the return value or %NULL
790 * @flags: pointer to a guint taking the variable's flags or %NULL
791 * @pobject: pointer to set to the object that really holds the property or
794 * Looks up @variable on @object. It also walks the object's prototype chain.
795 * If the variable exists, its value, flags and the real object containing the
796 * variable will be set and %TRUE will be returned.
798 * Returns: %TRUE if the variable exists, %FALSE otherwise
801 swfdec_as_object_get_variable_and_flags (SwfdecAsObject
*object
,
802 const char *variable
, SwfdecAsValue
*value
, guint
*flags
, SwfdecAsObject
**pobject
)
804 SwfdecAsObjectClass
*klass
;
806 SwfdecAsValue tmp_val
;
808 SwfdecAsObject
*tmp_pobject
, *cur
;
810 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
811 g_return_val_if_fail (variable
!= NULL
, FALSE
);
818 pobject
= &tmp_pobject
;
821 for (i
= 0; i
<= SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
&& cur
!= NULL
; i
++) {
822 klass
= SWFDEC_AS_OBJECT_GET_CLASS (cur
);
823 if (klass
->get (cur
, object
, variable
, value
, flags
)) {
827 cur
= swfdec_as_object_prototype_for_version (cur
, cur
->context
->version
,
830 if (i
> SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
) {
831 swfdec_as_context_abort (object
->context
, "Prototype recursion limit exceeded");
836 //SWFDEC_WARNING ("no such variable %s", variable);
837 SWFDEC_AS_VALUE_SET_UNDEFINED (value
);
844 * swfdec_as_object_delete_variable:
845 * @object: a #SwfdecAsObject
846 * @variable: garbage-collected name of the variable
848 * Deletes the given variable if possible. If the variable is protected from
849 * deletion, it will not be deleted.
851 * Returns: See #SwfdecAsDeleteReutnr for details of the return value.
854 swfdec_as_object_delete_variable (SwfdecAsObject
*object
, const char *variable
)
856 SwfdecAsObjectClass
*klass
;
858 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
859 g_return_val_if_fail (variable
!= NULL
, FALSE
);
861 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
862 return klass
->del (object
, variable
);
866 * swfdec_as_object_set_variable_flags:
867 * @object: a #SwfdecAsObject
868 * @variable: the variable to modify
869 * @flags: flags to set
871 * Sets the given flags for the given variable.
874 swfdec_as_object_set_variable_flags (SwfdecAsObject
*object
,
875 const char *variable
, SwfdecAsVariableFlag flags
)
877 SwfdecAsObjectClass
*klass
;
879 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
880 g_return_if_fail (variable
!= NULL
);
882 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
883 klass
->set_flags (object
, variable
, flags
, flags
);
887 * swfdec_as_object_unset_variable_flags:
888 * @object: a #SwfdecAsObject
889 * @variable: the variable to modify
890 * @flags: flags to unset
892 * Unsets the given flags for the given variable. The variable must exist in
896 swfdec_as_object_unset_variable_flags (SwfdecAsObject
*object
,
897 const char *variable
, SwfdecAsVariableFlag flags
)
899 SwfdecAsObjectClass
*klass
;
901 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
902 g_return_if_fail (variable
!= NULL
);
904 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
905 klass
->set_flags (object
, variable
, 0, flags
);
909 * swfdec_as_object_foreach:
910 * @object: a #SwfdecAsObject
911 * @func: function to call
912 * @data: data to pass to @func
914 * Calls @func for every variable of @object or until @func returns %FALSE. The
915 * variables of @object must not be modified by @func.
917 * Returns: %TRUE if @func always returned %TRUE
920 swfdec_as_object_foreach (SwfdecAsObject
*object
, SwfdecAsVariableForeach func
,
923 SwfdecAsObjectClass
*klass
;
925 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
926 g_return_val_if_fail (func
!= NULL
, FALSE
);
928 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
929 g_return_val_if_fail (klass
->foreach
!= NULL
, FALSE
);
930 return klass
->foreach (object
, func
, data
);
933 /*** SIMPLIFICATIONS ***/
936 swfdec_as_object_do_nothing (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
937 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
942 * swfdec_as_object_add_function:
943 * @object: a #SwfdecAsObject
944 * @name: name of the function. The string does not have to be
946 * @type: the required type of the this Object to make this function execute.
947 * May be 0 to accept any type.
948 * @native: a native function or %NULL to just not do anything
949 * @min_args: minimum number of arguments to pass to @native
951 * Adds @native as a variable named @name to @object. The newly added variable
952 * will not be enumerated.
954 * Returns: the newly created #SwfdecAsFunction or %NULL on error.
957 swfdec_as_object_add_function (SwfdecAsObject
*object
, const char *name
, GType type
,
958 SwfdecAsNative native
, guint min_args
)
960 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
961 g_return_val_if_fail (name
!= NULL
, NULL
);
962 g_return_val_if_fail (type
== 0 || g_type_is_a (type
, SWFDEC_TYPE_AS_OBJECT
), NULL
);
964 return swfdec_as_object_add_constructor (object
, name
, type
, 0, native
, min_args
, NULL
);
968 * swfdec_as_object_add_constructor:
969 * @object: a #SwfdecAsObject
970 * @name: name of the function. The string does not have to be
972 * @type: the required type of the this Object to make this function execute.
973 * May be 0 to accept any type.
974 * @construct_type: type used when using this function as a constructor. May
975 * be 0 to use the default type.
976 * @native: a native function or %NULL to just not do anything
977 * @min_args: minimum number of arguments to pass to @native
978 * @prototype: An optional object to be set as the "prototype" property of the
979 * new function. The prototype will be hidden and constant.
981 * Adds @native as a constructor named @name to @object. The newly added variable
982 * will not be enumerated.
984 * Returns: the newly created #SwfdecAsFunction or %NULL on error.
987 swfdec_as_object_add_constructor (SwfdecAsObject
*object
, const char *name
, GType type
,
988 GType construct_type
, SwfdecAsNative native
, guint min_args
, SwfdecAsObject
*prototype
)
990 SwfdecAsFunction
*function
;
993 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
994 g_return_val_if_fail (name
!= NULL
, NULL
);
995 g_return_val_if_fail (type
== 0 || g_type_is_a (type
, SWFDEC_TYPE_AS_OBJECT
), NULL
);
996 g_return_val_if_fail (construct_type
== 0 || g_type_is_a (construct_type
, SWFDEC_TYPE_AS_OBJECT
), NULL
);
997 g_return_val_if_fail (prototype
== NULL
|| SWFDEC_IS_AS_OBJECT (prototype
), NULL
);
1000 native
= swfdec_as_object_do_nothing
;
1001 function
= swfdec_as_native_function_new (object
->context
, name
, native
, min_args
, prototype
);
1002 if (function
== NULL
)
1005 swfdec_as_native_function_set_object_type (SWFDEC_AS_NATIVE_FUNCTION (function
), type
);
1006 if (construct_type
!= 0)
1007 swfdec_as_native_function_set_construct_type (SWFDEC_AS_NATIVE_FUNCTION (function
), construct_type
);
1008 name
= swfdec_as_context_get_string (object
->context
, name
);
1009 SWFDEC_AS_VALUE_SET_OBJECT (&val
, SWFDEC_AS_OBJECT (function
));
1010 /* FIXME: I'd like to make sure no such property exists yet */
1011 swfdec_as_object_set_variable_and_flags (object
, name
, &val
,
1012 SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1017 * swfdec_as_object_run:
1018 * @object: a #SwfdecAsObject
1019 * @script: script to execute
1021 * Executes the given @script with @object as this pointer.
1024 swfdec_as_object_run (SwfdecAsObject
*object
, SwfdecScript
*script
)
1026 SwfdecAsContext
*context
;
1027 SwfdecAsFrame
*frame
;
1029 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1030 g_return_if_fail (script
!= NULL
);
1032 context
= object
->context
;
1033 frame
= swfdec_as_frame_new (context
, script
);
1036 swfdec_as_frame_set_this (frame
, object
);
1037 swfdec_as_frame_preload (frame
);
1038 swfdec_as_context_run (context
);
1039 swfdec_as_stack_pop (context
);
1043 * swfdec_as_object_call:
1044 * @object: a #SwfdecAsObject
1045 * @name: garbage-collected string naming the function to call.
1046 * @argc: number of arguments to provide to function
1047 * @argv: arguments or %NULL when @argc is 0
1048 * @return_value: location to take the return value of the call or %NULL to
1049 * ignore the return value.
1051 * Calls the function named @name on the given object. This function is
1052 * essentially equal to the folloeing Actionscript code:
1053 * <informalexample><programlisting>
1054 * @return_value = @object.@name (@argv[0], ..., @argv[argc-1]);
1055 * </programlisting></informalexample>
1058 swfdec_as_object_call (SwfdecAsObject
*object
, const char *name
, guint argc
,
1059 SwfdecAsValue
*argv
, SwfdecAsValue
*return_value
)
1061 static SwfdecAsValue tmp
; /* ignored */
1062 SwfdecAsFunction
*fun
;
1064 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1065 g_return_if_fail (name
!= NULL
);
1066 g_return_if_fail (argc
== 0 || argv
!= NULL
);
1069 SWFDEC_AS_VALUE_SET_UNDEFINED (return_value
);
1070 swfdec_as_object_get_variable (object
, name
, &tmp
);
1071 if (!SWFDEC_AS_VALUE_IS_OBJECT (&tmp
))
1073 fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&tmp
);
1074 if (!SWFDEC_IS_AS_FUNCTION (fun
))
1076 swfdec_as_function_call (fun
, object
, argc
, argv
, return_value
? return_value
: &tmp
);
1077 swfdec_as_context_run (object
->context
);
1081 * swfdec_as_object_has_function:
1082 * @object: a #SwfdecAsObject
1083 * @name: garbage-collected name of th function
1085 * Convenience function that checks of @object has a variable that references
1088 * Returns: %TRUE if object.name is a function.
1091 swfdec_as_object_has_function (SwfdecAsObject
*object
, const char *name
)
1095 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
1096 g_return_val_if_fail (name
!= NULL
, FALSE
);
1098 swfdec_as_object_get_variable (object
, name
, &val
);
1099 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
1101 return SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&val
));
1105 * swfdec_as_object_create:
1107 * @n_args: number of arguments
1108 * @args: arguments to pass to constructor
1110 * Creates a new object for the given constructor and pushes the constructor on
1111 * top of the stack. To actually run the constructor, you need to call
1112 * swfdec_as_context_run(). After the constructor has been run, the new object
1113 * will be pushed to the top of the stack.
1116 swfdec_as_object_create (SwfdecAsFunction
*fun
, guint n_args
,
1117 const SwfdecAsValue
*args
)
1120 SwfdecAsObject
*new;
1121 SwfdecAsContext
*context
;
1122 SwfdecAsFunction
*cur
;
1126 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (fun
));
1128 context
= SWFDEC_AS_OBJECT (fun
)->context
;
1131 if (SWFDEC_IS_AS_NATIVE_FUNCTION (cur
)) {
1132 SwfdecAsNativeFunction
*native
= SWFDEC_AS_NATIVE_FUNCTION (cur
);
1133 if (native
->construct_size
) {
1134 type
= native
->construct_type
;
1135 size
= native
->construct_size
;
1139 swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (cur
), SWFDEC_AS_STR_prototype
, &val
);
1140 if (SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1141 SwfdecAsObject
*proto
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1142 swfdec_as_object_get_variable (proto
, SWFDEC_AS_STR___constructor__
, &val
);
1143 if (SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1144 cur
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1145 if (SWFDEC_IS_AS_FUNCTION (cur
)) {
1151 } while (type
== 0 && cur
!= NULL
);
1153 type
= SWFDEC_TYPE_AS_OBJECT
;
1154 size
= sizeof (SwfdecAsObject
);
1156 if (swfdec_as_context_use_mem (context
, size
)) {
1157 new = g_object_new (type
, NULL
);
1158 swfdec_as_object_add (new, context
, size
);
1159 /* set initial variables */
1160 if (swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (fun
), SWFDEC_AS_STR_prototype
, &val
)) {
1161 swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR___proto__
,
1162 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1164 SWFDEC_AS_VALUE_SET_OBJECT (&val
, SWFDEC_AS_OBJECT (fun
));
1165 if (context
->version
< 7) {
1166 swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR_constructor
,
1167 &val
, SWFDEC_AS_VARIABLE_HIDDEN
);
1169 swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR___constructor__
,
1170 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_VERSION_6_UP
);
1172 /* need to do this, since we must push something to the frame stack */
1175 swfdec_as_function_call (fun
, new, n_args
, args
, NULL
);
1176 context
->frame
->construct
= TRUE
;
1180 * swfdec_as_object_set_constructor:
1181 * @object: a #SwfdecAsObject
1182 * @construct: the constructor of @object
1184 * Sets the constructor variables for @object. Most objects get these
1185 * variables set automatically, but for objects you created yourself, you want
1186 * to call this function. This is essentially the same as the following script
1188 * |[ object.constructor = construct;
1189 * object.__proto__ = construct.prototype; ]|
1192 swfdec_as_object_set_constructor (SwfdecAsObject
*object
, SwfdecAsObject
*construct
)
1195 SwfdecAsObject
*proto
;
1197 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1198 g_return_if_fail (SWFDEC_IS_AS_OBJECT (construct
));
1200 swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (construct
),
1201 SWFDEC_AS_STR_prototype
, &val
);
1202 if (SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1203 proto
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1205 SWFDEC_WARNING ("constructor has no prototype, using Object.prototype");
1206 proto
= object
->context
->Object_prototype
;
1208 SWFDEC_AS_VALUE_SET_OBJECT (&val
, construct
);
1209 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR_constructor
,
1210 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1211 SWFDEC_AS_VALUE_SET_OBJECT (&val
, proto
);
1212 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR___proto__
,
1213 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1217 * swfdec_as_object_add_variable:
1218 * @object: a #SwfdecAsObject
1219 * @variable: name of the variable
1220 * @get: getter function to call when reading the variable
1221 * @set: setter function to call when writing the variable or %NULL if read-only
1222 * @default_flags: flags to use if creating the variable anew - the flags will
1223 * be ignored if the property already exists.
1225 * Adds a variable to @object in the same way as the Actionscript code
1226 * "object.addProperty()" would do. Accessing the variable will from now on be
1227 * handled by calling the @get or @set functions. A previous value of the
1228 * variable or a previous call to this function will be overwritten.
1231 swfdec_as_object_add_variable (SwfdecAsObject
*object
, const char *variable
,
1232 SwfdecAsFunction
*get
, SwfdecAsFunction
*set
, guint default_flags
)
1234 SwfdecAsVariable
*var
;
1236 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1237 g_return_if_fail (variable
!= NULL
);
1238 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (get
));
1239 g_return_if_fail (set
== NULL
|| SWFDEC_IS_AS_FUNCTION (set
));
1241 var
= swfdec_as_object_hash_lookup (object
, variable
);
1243 var
= swfdec_as_object_hash_create (object
, variable
, default_flags
);
1252 SWFDEC_AS_NATIVE (101, 2, swfdec_as_object_addProperty
)
1254 swfdec_as_object_addProperty (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1255 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1257 SwfdecAsFunction
*get
, *set
;
1260 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1263 name
= swfdec_as_value_to_string (cx
, &argv
[0]);
1264 if (!SWFDEC_AS_VALUE_IS_OBJECT (&argv
[1]) ||
1265 !SWFDEC_IS_AS_FUNCTION ((get
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1]))))
1267 if (SWFDEC_AS_VALUE_IS_OBJECT (&argv
[2])) {
1268 set
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&argv
[2]);
1269 if (!SWFDEC_IS_AS_FUNCTION (set
))
1271 } else if (SWFDEC_AS_VALUE_IS_NULL (&argv
[2])) {
1277 swfdec_as_object_add_variable (object
, name
, get
, set
, 0);
1278 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1281 SWFDEC_AS_NATIVE (101, 5, swfdec_as_object_hasOwnProperty
)
1283 swfdec_as_object_hasOwnProperty (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1284 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1286 SwfdecAsVariable
*var
;
1289 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1291 // return false even if no params
1295 name
= swfdec_as_value_to_string (object
->context
, &argv
[0]);
1297 if (!(var
= swfdec_as_object_hash_lookup (object
, name
)))
1300 /* This functions only checks NOT 6 flag, and checks it on ALL VERSIONS */
1301 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_NOT_6
)
1304 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1307 SWFDEC_AS_NATIVE (101, 7, swfdec_as_object_isPropertyEnumerable
)
1309 swfdec_as_object_isPropertyEnumerable (SwfdecAsContext
*cx
,
1310 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
1311 SwfdecAsValue
*retval
)
1313 SwfdecAsVariable
*var
;
1316 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1318 // return false even if no params
1322 name
= swfdec_as_value_to_string (object
->context
, &argv
[0]);
1324 if (!(var
= swfdec_as_object_hash_lookup (object
, name
)))
1327 if (var
->flags
& SWFDEC_AS_VARIABLE_HIDDEN
)
1330 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1333 SWFDEC_AS_NATIVE (101, 6, swfdec_as_object_isPrototypeOf
)
1335 swfdec_as_object_isPrototypeOf (SwfdecAsContext
*cx
,
1336 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
1337 SwfdecAsValue
*retval
)
1339 SwfdecAsObject
*class;
1341 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1343 // return false even if no params
1347 class = swfdec_as_value_to_object (cx
, &argv
[0]);
1351 while ((class = swfdec_as_object_prototype_for_version (class, cx
->version
, TRUE
)) != NULL
) {
1352 if (object
== class) {
1353 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1358 // not found, nothing to do
1361 SWFDEC_AS_NATIVE (101, 0, swfdec_as_object_watch
)
1363 swfdec_as_object_watch (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1364 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1366 SwfdecAsWatch
*watch
;
1369 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1374 name
= swfdec_as_value_to_string (cx
, &argv
[0]);
1376 if (!SWFDEC_AS_VALUE_IS_OBJECT (&argv
[1]))
1379 if (!SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1])))
1382 if (object
->watches
== NULL
) {
1383 object
->watches
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
1384 NULL
, (GDestroyNotify
) swfdec_as_watch_unref
);
1387 watch
= g_hash_table_lookup (object
->watches
, name
);
1389 if (watch
== NULL
) {
1390 watch
= swfdec_as_watch_new (SWFDEC_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1])));
1393 g_hash_table_insert (object
->watches
, (char *) name
, watch
);
1395 watch
->watch
= SWFDEC_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1]));
1399 watch
->watch_data
= argv
[2];
1401 SWFDEC_AS_VALUE_SET_UNDEFINED (&watch
->watch_data
);
1404 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1407 SWFDEC_AS_NATIVE (101, 1, swfdec_as_object_unwatch
)
1409 swfdec_as_object_unwatch (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1410 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1412 SwfdecAsVariable
*var
;
1415 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1420 name
= swfdec_as_value_to_string (cx
, &argv
[0]);
1422 // special case: can't unwatch native properties
1423 if ((var
= swfdec_as_object_hash_lookup (object
, name
))&& var
->get
!= NULL
)
1426 if (object
->watches
!= NULL
&&
1427 g_hash_table_remove (object
->watches
, name
)) {
1429 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1431 if (g_hash_table_size (object
->watches
) == 0) {
1432 g_hash_table_destroy (object
->watches
);
1433 object
->watches
= NULL
;
1438 SWFDEC_AS_NATIVE (101, 3, swfdec_as_object_valueOf
)
1440 swfdec_as_object_valueOf (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1441 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1443 SWFDEC_AS_VALUE_SET_OBJECT (retval
, object
);
1446 SWFDEC_AS_NATIVE (101, 4, swfdec_as_object_toString
)
1448 swfdec_as_object_toString (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1449 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1451 if (SWFDEC_IS_AS_FUNCTION (object
)) {
1452 SWFDEC_AS_VALUE_SET_STRING (retval
, SWFDEC_AS_STR__type_Function_
);
1454 SWFDEC_AS_VALUE_SET_STRING (retval
, SWFDEC_AS_STR__object_Object_
);
1459 swfdec_as_object_decode (SwfdecAsObject
*object
, const char *str
)
1465 str
= swfdec_as_string_unescape (object
->context
, str
);
1469 varlist
= g_strsplit (str
, "&", -1);
1471 for (i
= 0; varlist
[i
] != NULL
; i
++) {
1472 p
= strchr (varlist
[i
], '=');
1480 SWFDEC_AS_VALUE_SET_STRING (&val
,
1481 swfdec_as_context_get_string (object
->context
, p
));
1483 SWFDEC_AS_VALUE_SET_STRING (&val
, SWFDEC_AS_STR_EMPTY
);
1485 swfdec_as_object_set_variable (object
,
1486 swfdec_as_context_get_string (object
->context
, varlist
[i
]), &val
);
1491 swfdec_as_object_init_context (SwfdecAsContext
*context
, guint version
)
1494 SwfdecAsObject
*object
, *proto
;
1496 proto
= swfdec_as_object_new_empty (context
);
1499 object
= SWFDEC_AS_OBJECT (swfdec_as_object_add_function (context
->global
,
1500 SWFDEC_AS_STR_Object
, 0, NULL
, 0));
1503 context
->Object
= object
;
1504 context
->Object_prototype
= proto
;
1505 SWFDEC_AS_VALUE_SET_OBJECT (&val
, proto
);
1506 /* first, set our own */
1507 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR_prototype
,
1508 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
|
1509 SWFDEC_AS_VARIABLE_CONSTANT
);
1511 /* then finish the function prototype (use this order or
1512 * SWFDEC_AS_VARIABLE_CONSTANT won't let us */
1513 swfdec_as_object_set_variable_and_flags (context
->Function_prototype
,
1514 SWFDEC_AS_STR___proto__
, &val
,
1515 SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1517 SWFDEC_AS_VALUE_SET_OBJECT (&val
, object
);
1518 swfdec_as_object_set_variable_and_flags (proto
, SWFDEC_AS_STR_constructor
,
1519 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1523 * swfdec_as_object_get_debug:
1524 * @object: a #SwfdecAsObject
1526 * Gets a representation string suitable for debugging. This function is
1527 * guaranteed to not modify the state of the script engine, unlike
1528 * swfdec_as_value_to_string() for example.
1530 * Returns: A newly allocated string. Free it with g_free() after use.
1533 swfdec_as_object_get_debug (SwfdecAsObject
*object
)
1535 SwfdecAsObjectClass
*klass
;
1537 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
1539 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1540 return klass
->debug (object
);
1544 * swfdec_as_object_resolve:
1545 * @object: a #SwfdecAsObject
1547 * Resolves the object to its real object. Some internal objects should not be
1548 * exposed to scripts, for example #SwfdecAsFrame objects. If an object you want
1549 * to expose might be internal, call this function to resolve it to an object
1550 * that is safe to expose.
1552 * Returns: a non-internal object
1555 swfdec_as_object_resolve (SwfdecAsObject
*object
)
1557 SwfdecAsObjectClass
*klass
;
1559 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
1561 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1562 if (klass
->resolve
== NULL
)
1565 return klass
->resolve (object
);