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
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_as_super.h"
35 #include "swfdec_debug.h"
36 #include "swfdec_movie.h"
39 * SECTION:SwfdecAsObject
40 * @title: SwfdecAsObject
41 * @short_description: the base object type for scriptable objects
43 * This is the basic object type in Swfdec. Every object used by the script
44 * engine must be a #SwfdecAsObject. It handles memory management and assigning
45 * variables to it. Almost all functions that are called on objects require that
46 * the objects have been added to the garbage collector previously. For
47 * custom-created objects, you need to do this using swfdec_as_object_add(),
48 * built-in functions that create objects do this manually.
50 * Note that you cannot know the lifetime of a #SwfdecAsObject, since scripts
51 * may assign it as a variable to other objects. So you should not assume to
52 * know when an object gets removed.
58 * Every object value inside the Swfdec script engine must be a SwfdecAsObject.
59 * If you want to add custom objects to your script engine, you need to create a
60 * subclass. The class provides a number of virtual functions that you can
61 * override to achieve the desired behaviour.
65 * SwfdecAsVariableFlag:
66 * @SWFDEC_AS_VARIABLE_HIDDEN: Do not include variable in enumerations and
67 * swfdec_as_object_foreach().
68 * @SWFDEC_AS_VARIABLE_PERMANENT: Do not allow swfdec_as_object_delete_variable()
69 * to delete this variable.
70 * @SWFDEC_AS_VARIABLE_CONSTANT: Do not allow changing the value with
71 * swfdec_as_object_set_variable().
72 * @SWFDEC_AS_VARIABLE_VERSION_6_UP: This symbol is only visible in version 6
74 * @SWFDEC_AS_VARIABLE_VERSION_NOT_6: This symbols is visible in all versions
76 * @SWFDEC_AS_VARIABLE_VERSION_7_UP: This symbol is only visible in version 7
78 * @SWFDEC_AS_VARIABLE_VERSION_8_UP: This symbol is only visible in version 8
80 * @SWFDEC_AS_VARIABLE_VERSION_9_UP: This symbol is only visible in version 9
83 * These flags are used to describe various properties of a variable inside
84 * Swfdec. You can manually set them with swfdec_as_object_set_variable_flags().
88 * SwfdecAsDeleteReturn:
89 * @SWFDEC_AS_DELETE_NOT_FOUND: The variable was not found and therefore
90 * couldn't be deleted.
91 * @SWFDEC_AS_DELETE_DELETED: The variable was deleted.
92 * @SWFDEC_AS_DELETE_NOT_DELETED: The variable was found but could not be
95 * This is the return value used by swfdec_as_object_delete_variable(). It
96 * describes the various outcomes of trying to delete a variable.
100 * SwfdecAsVariableForeach:
101 * @object: The object this function is run on
102 * @variable: garbage-collected name of the current variables
103 * @value: value of the current variable
104 * @flags: Flags associated with the current variable
105 * @data: User data passed to swfdec_as_object_foreach()
107 * Function prototype for the swfdec_as_object_foreach() function.
109 * Returns: %TRUE to continue running the foreach function, %FALSE to stop
112 typedef struct _SwfdecAsVariable SwfdecAsVariable
;
113 struct _SwfdecAsVariable
{
114 guint flags
; /* SwfdecAsVariableFlag values */
115 SwfdecAsValue value
; /* value of property */
116 SwfdecAsFunction
* get
; /* getter set with swfdec_as_object_add_property */
117 SwfdecAsFunction
* set
; /* setter or %NULL */
121 SwfdecAsFunction
* watch
; /* watcher or %NULL */
122 SwfdecAsValue watch_data
; /* user data to watcher */
123 guint refcount
; /* refcount - misused for recursion detection */
126 G_DEFINE_TYPE (SwfdecAsObject
, swfdec_as_object
, SWFDEC_TYPE_GC_OBJECT
)
129 swfdec_as_watch_can_recurse (SwfdecAsWatch
*watch
)
133 version
= swfdec_gc_object_get_context (watch
->watch
)->version
;
135 return watch
->refcount
<= 1;
137 return watch
->refcount
<= 64 + 1;
142 swfdec_as_watch_ref (SwfdecAsWatch
*watch
)
148 swfdec_as_watch_unref (SwfdecAsWatch
*watch
)
151 if (watch
->refcount
== 0) {
152 swfdec_as_context_unuse_mem (swfdec_gc_object_get_context (watch
->watch
),
153 sizeof (SwfdecAsWatch
));
154 g_slice_free (SwfdecAsWatch
, watch
);
158 /* This is a huge hack design-wise, but we can't use watch->watch,
159 * it might be gone already */
161 swfdec_as_object_steal_watches (gpointer key
, gpointer value
, gpointer object
)
163 SwfdecAsWatch
*watch
= value
;
165 g_assert (watch
->refcount
== 1);
166 watch
->watch
= (SwfdecAsFunction
*) object
;
167 swfdec_as_watch_unref (watch
);
172 swfdec_as_object_free_property (gpointer key
, gpointer value
, gpointer data
)
174 SwfdecAsObject
*object
= data
;
176 swfdec_as_context_unuse_mem (swfdec_gc_object_get_context (object
), sizeof (SwfdecAsVariable
));
177 g_slice_free (SwfdecAsVariable
, value
);
181 swfdec_as_object_dispose (GObject
*gobject
)
183 SwfdecAsContext
*context
= swfdec_gc_object_get_context (gobject
);
184 SwfdecAsObject
*object
= SWFDEC_AS_OBJECT (gobject
);
186 if (context
->debugger
) {
187 SwfdecAsDebuggerClass
*klass
= SWFDEC_AS_DEBUGGER_GET_CLASS (context
->debugger
);
189 klass
->remove (context
->debugger
, context
, object
);
192 if (object
->properties
) {
193 g_hash_table_foreach (object
->properties
, swfdec_as_object_free_property
, object
);
194 g_hash_table_destroy (object
->properties
);
195 object
->properties
= NULL
;
197 if (object
->watches
) {
198 g_hash_table_foreach_steal (object
->watches
, swfdec_as_object_steal_watches
, object
);
199 g_hash_table_destroy (object
->watches
);
200 object
->watches
= NULL
;
202 g_slist_free (object
->interfaces
);
203 object
->interfaces
= NULL
;
205 G_OBJECT_CLASS (swfdec_as_object_parent_class
)->dispose (gobject
);
209 swfdec_gc_object_mark_property (gpointer key
, gpointer value
, gpointer unused
)
211 SwfdecAsVariable
*var
= value
;
213 swfdec_as_string_mark (key
);
215 swfdec_gc_object_mark (var
->get
);
217 swfdec_gc_object_mark (var
->set
);
219 swfdec_as_value_mark (&var
->value
);
224 swfdec_gc_object_mark_watch (gpointer key
, gpointer value
, gpointer unused
)
226 SwfdecAsWatch
*watch
= value
;
228 swfdec_as_string_mark (key
);
229 swfdec_gc_object_mark (watch
->watch
);
230 swfdec_as_value_mark (&watch
->watch_data
);
234 swfdec_as_object_mark (SwfdecGcObject
*gc
)
236 SwfdecAsObject
*object
= SWFDEC_AS_OBJECT (gc
);
238 if (object
->prototype
)
239 swfdec_gc_object_mark (object
->prototype
);
240 g_hash_table_foreach (object
->properties
, swfdec_gc_object_mark_property
, NULL
);
242 g_hash_table_foreach (object
->watches
, swfdec_gc_object_mark_watch
, NULL
);
243 g_slist_foreach (object
->interfaces
, (GFunc
) swfdec_gc_object_mark
, NULL
);
247 swfdec_as_object_lookup_case_insensitive (gpointer key
, gpointer value
, gpointer user_data
)
249 return g_ascii_strcasecmp (key
, user_data
) == 0;
253 swfdec_as_variable_name_is_valid (const char *name
)
255 return name
!= SWFDEC_AS_STR_EMPTY
;
258 static SwfdecAsVariable
*
259 swfdec_as_object_hash_lookup (SwfdecAsObject
*object
, const char *variable
)
261 SwfdecAsVariable
*var
= g_hash_table_lookup (object
->properties
, variable
);
263 if (var
|| swfdec_gc_object_get_context (object
)->version
>= 7)
265 var
= g_hash_table_find (object
->properties
, swfdec_as_object_lookup_case_insensitive
, (gpointer
) variable
);
269 static SwfdecAsVariable
*
270 swfdec_as_object_hash_create (SwfdecAsObject
*object
, const char *variable
, guint flags
)
272 SwfdecAsVariable
*var
;
274 if (!swfdec_as_variable_name_is_valid (variable
))
276 swfdec_as_context_use_mem (swfdec_gc_object_get_context (object
), sizeof (SwfdecAsVariable
));
277 var
= g_slice_new0 (SwfdecAsVariable
);
279 g_hash_table_insert (object
->properties
, (gpointer
) variable
, var
);
285 swfdec_as_object_variable_enabled_in_version (SwfdecAsVariable
*var
,
288 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_6_UP
&& version
< 6)
290 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_NOT_6
&& version
== 6)
292 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_7_UP
&& version
< 7)
294 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_8_UP
&& version
< 8)
296 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_9_UP
&& version
< 9)
303 swfdec_as_object_do_get (SwfdecAsObject
*object
, SwfdecAsObject
*orig
,
304 const char *variable
, SwfdecAsValue
*val
, guint
*flags
)
306 SwfdecAsVariable
*var
= swfdec_as_object_hash_lookup (object
, variable
);
311 /* variable flag checks */
312 if (!swfdec_as_object_variable_enabled_in_version (var
,
313 swfdec_gc_object_get_context (object
)->version
))
317 swfdec_as_function_call (var
->get
, orig
, 0, NULL
, val
);
326 static SwfdecAsWatch
*
327 swfdec_as_watch_new (SwfdecAsFunction
*function
)
329 SwfdecAsWatch
*watch
;
331 swfdec_as_context_use_mem (swfdec_gc_object_get_context (function
),
332 sizeof (SwfdecAsWatch
));
334 watch
= g_slice_new (SwfdecAsWatch
);
336 watch
->watch
= function
;
337 SWFDEC_AS_VALUE_SET_UNDEFINED (&watch
->watch_data
);
342 * Like swfdec_as_object_get_prototype, but doesn't check 8_UP flag when
343 * version is 7 and doesn't check if the property has been deleted if version
346 static SwfdecAsObject
*
347 swfdec_as_object_get_prototype_internal (SwfdecAsObject
*object
)
351 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
353 version
= swfdec_gc_object_get_context (object
)->version
;
355 if (object
->prototype
== NULL
)
358 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_6_UP
&& version
< 6)
360 // don't check for NOT_6 flag
361 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_7_UP
&& version
< 7)
363 // don't check 8_UP or 9_UP for version 6, 7 or 8
364 if (object
->prototype_flags
& (SWFDEC_AS_VARIABLE_VERSION_8_UP
| SWFDEC_AS_VARIABLE_VERSION_9_UP
) && version
< 6)
366 // check that it exists, if version < 7
368 !swfdec_as_object_hash_lookup (object
, SWFDEC_AS_STR___proto__
))
371 return object
->prototype
;
375 * Get's the object->prototype, if propflags allow it for current version and
376 * if it hasn't been deleted from the object already
379 swfdec_as_object_get_prototype (SwfdecAsObject
*object
)
382 SwfdecAsObject
*prototype
;
384 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
386 version
= swfdec_gc_object_get_context (object
)->version
;
388 prototype
= swfdec_as_object_get_prototype_internal (object
);
390 if (prototype
== NULL
)
392 // check 8_UP for version 7, still not for version 6
393 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_8_UP
&&
396 // check 9_UP flag for version 8, still not for version 7 or 6
397 if (object
->prototype_flags
& SWFDEC_AS_VARIABLE_VERSION_9_UP
&&
400 // require it to exist even on version >= 7
402 !swfdec_as_object_hash_lookup (object
, SWFDEC_AS_STR___proto__
))
405 return object
->prototype
;
408 static SwfdecAsVariable
*
409 swfdec_as_object_hash_lookup_with_prototype (SwfdecAsObject
*object
,
410 const char *variable
, SwfdecAsObject
**proto
)
412 SwfdecAsVariable
*var
;
413 SwfdecAsObject
*proto_
;
415 g_return_val_if_fail (swfdec_as_variable_name_is_valid (variable
), NULL
);
419 // match first level variable even if it has version flags that hide it in
421 var
= swfdec_as_object_hash_lookup (object
, variable
);
422 if (var
== NULL
&& variable
!= SWFDEC_AS_STR___proto__
) {
425 proto_
= swfdec_as_object_get_prototype (object
);
427 for (i
= 0; i
< SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
&& proto_
; i
++) {
428 var
= swfdec_as_object_hash_lookup (proto_
, variable
);
431 proto_
= swfdec_as_object_get_prototype (proto_
);
435 if (i
== SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
) {
436 swfdec_as_context_abort (swfdec_gc_object_get_context (object
), "Prototype recursion limit exceeded");
448 swfdec_as_object_do_set (SwfdecAsObject
*object
, const char *variable
,
449 const SwfdecAsValue
*val
, guint flags
)
451 SwfdecAsVariable
*var
;
452 SwfdecAsWatch
*watch
;
453 SwfdecAsObject
*proto
;
455 if (!swfdec_as_variable_name_is_valid (variable
))
458 var
= swfdec_as_object_hash_lookup_with_prototype (object
, variable
, &proto
);
459 if (swfdec_as_context_is_aborted (swfdec_gc_object_get_context (object
)))
462 // if variable is disabled in this version
463 if (var
!= NULL
&& !swfdec_as_object_variable_enabled_in_version (var
,
464 swfdec_gc_object_get_context (object
)->version
)) {
466 // it's at the top level, remove getter and setter plus overwrite
470 // it's in proto, we create a new one at the top level
476 var
= swfdec_as_object_hash_create (object
, variable
, flags
);
480 if (var
->flags
& SWFDEC_AS_VARIABLE_CONSTANT
)
482 // remove the flags that could make this variable hidden
483 if (swfdec_gc_object_get_context (object
)->version
== 6) {
484 // version 6, so let's forget SWFDEC_AS_VARIABLE_VERSION_7_UP flag, oops!
485 // we will still set the value though, even if that flag is set
486 var
->flags
&= ~(SWFDEC_AS_VARIABLE_VERSION_6_UP
|
487 SWFDEC_AS_VARIABLE_VERSION_NOT_6
| SWFDEC_AS_VARIABLE_VERSION_8_UP
|
488 SWFDEC_AS_VARIABLE_VERSION_9_UP
);
490 var
->flags
&= ~(SWFDEC_AS_VARIABLE_VERSION_6_UP
|
491 SWFDEC_AS_VARIABLE_VERSION_NOT_6
| SWFDEC_AS_VARIABLE_VERSION_7_UP
|
492 SWFDEC_AS_VARIABLE_VERSION_8_UP
| SWFDEC_AS_VARIABLE_VERSION_9_UP
);
495 if (object
->watches
) {
496 SwfdecAsValue ret
= *val
;
497 watch
= g_hash_table_lookup (object
->watches
, variable
);
498 /* FIXME: figure out if this limit here is correct. Add a watch in Flash 7
499 * and set a variable using Flash 6 */
500 if (watch
&& swfdec_as_watch_can_recurse (watch
)) {
501 SwfdecAsValue args
[4];
502 SWFDEC_AS_VALUE_SET_STRING (&args
[0], variable
);
503 args
[1] = var
->value
;
505 args
[3] = watch
->watch_data
;
506 swfdec_as_watch_ref (watch
);
507 swfdec_as_function_call (watch
->watch
, object
, 4, args
, &ret
);
508 swfdec_as_watch_unref (watch
);
509 var
= swfdec_as_object_hash_lookup_with_prototype (object
, variable
,
511 if (swfdec_as_context_is_aborted (swfdec_gc_object_get_context (object
)))
514 SWFDEC_INFO ("watch removed variable %s", variable
);
526 swfdec_as_function_call (var
->set
, object
, 1, val
, &tmp
);
528 } else if (watch
== NULL
) {
532 if (variable
== SWFDEC_AS_STR___proto__
) {
533 if (SWFDEC_AS_VALUE_IS_OBJECT (val
) &&
534 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (val
))) {
535 object
->prototype
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
536 object
->prototype_flags
= var
->flags
;
538 object
->prototype
= NULL
;
539 object
->prototype_flags
= 0;
545 swfdec_as_object_do_set_flags (SwfdecAsObject
*object
, const char *variable
, guint flags
, guint mask
)
547 SwfdecAsVariable
*var
= swfdec_as_object_hash_lookup (object
, variable
);
550 var
->flags
= (var
->flags
& ~mask
) | flags
;
552 if (variable
== SWFDEC_AS_STR___proto__
)
553 object
->prototype_flags
= var
->flags
;
557 static SwfdecAsDeleteReturn
558 swfdec_as_object_do_delete (SwfdecAsObject
*object
, const char *variable
)
560 SwfdecAsVariable
*var
;
562 var
= g_hash_table_lookup (object
->properties
, variable
);
564 return SWFDEC_AS_DELETE_NOT_FOUND
;
565 if (var
->flags
& SWFDEC_AS_VARIABLE_PERMANENT
)
566 return SWFDEC_AS_DELETE_NOT_DELETED
;
568 // Note: We won't remove object->prototype, even if __proto__ is deleted
570 swfdec_as_object_free_property (NULL
, var
, object
);
571 if (!g_hash_table_remove (object
->properties
, variable
)) {
572 g_assert_not_reached ();
574 return SWFDEC_AS_DELETE_DELETED
;
578 SwfdecAsObject
* object
;
579 SwfdecAsVariableForeach func
;
585 swfdec_as_object_hash_foreach (gpointer key
, gpointer value
, gpointer data
)
587 ForeachData
*fdata
= data
;
588 SwfdecAsVariable
*var
= value
;
593 fdata
->retval
= fdata
->func (fdata
->object
, key
, &var
->value
, var
->flags
, fdata
->data
);
596 /* FIXME: does not do Adobe Flash's order for Enumerate actions */
598 swfdec_as_object_do_foreach (SwfdecAsObject
*object
, SwfdecAsVariableForeach func
, gpointer data
)
600 ForeachData fdata
= { object
, func
, data
, TRUE
};
602 g_hash_table_foreach (object
->properties
, swfdec_as_object_hash_foreach
, &fdata
);
607 SwfdecAsObject
* object
;
608 SwfdecAsVariableForeachRemove func
;
613 swfdec_as_object_hash_foreach_remove (gpointer key
, gpointer value
, gpointer data
)
615 ForeachRemoveData
*fdata
= data
;
616 SwfdecAsVariable
*var
= value
;
618 if (!fdata
->func (fdata
->object
, key
, &var
->value
, var
->flags
, fdata
->data
))
621 swfdec_as_object_free_property (NULL
, var
, fdata
->object
);
626 * swfdec_as_object_foreach_remove:
627 * @object: a #SwfdecAsObject
628 * @func: function that determines which object to remove
629 * @data: data to pass to @func
631 * Removes all variables form @object where @func returns %TRUE. This is an
632 * internal function for array operations.
634 * Returns: he number of variables removed
637 swfdec_as_object_foreach_remove (SwfdecAsObject
*object
, SwfdecAsVariableForeach func
,
640 ForeachRemoveData fdata
= { object
, func
, data
};
642 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), 0);
643 g_return_val_if_fail (func
!= NULL
, 0);
645 return g_hash_table_foreach_remove (object
->properties
,
646 swfdec_as_object_hash_foreach_remove
, &fdata
);
650 SwfdecAsObject
* object
;
651 GHashTable
* properties_new
;
652 SwfdecAsVariableForeachRename func
;
657 swfdec_as_object_hash_foreach_rename (gpointer key
, gpointer value
, gpointer data
)
659 ForeachRenameData
*fdata
= data
;
660 SwfdecAsVariable
*var
= value
;
663 key_new
= fdata
->func (fdata
->object
, key
, &var
->value
, var
->flags
, fdata
->data
);
665 g_hash_table_insert (fdata
->properties_new
, (gpointer
) key_new
, var
);
667 swfdec_as_object_free_property (NULL
, var
, fdata
->object
);
674 * swfdec_as_object_foreach_rename:
675 * @object: a #SwfdecAsObject
676 * @func: function determining the new name
677 * @data: data to pass to @func
679 * Calls @func for each variable of @object. The function is then supposed
680 * to return the new name of the variable or %NULL if the variable should be
681 * removed. This is an internal function for array operations.
684 swfdec_as_object_foreach_rename (SwfdecAsObject
*object
, SwfdecAsVariableForeachRename func
,
687 ForeachRenameData fdata
= { object
, NULL
, func
, data
};
689 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
690 g_return_if_fail (func
!= NULL
);
692 fdata
.properties_new
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
693 g_hash_table_foreach_remove (object
->properties
, swfdec_as_object_hash_foreach_rename
, &fdata
);
694 g_hash_table_destroy (object
->properties
);
695 object
->properties
= fdata
.properties_new
;
699 swfdec_as_object_do_debug (SwfdecAsObject
*object
)
701 if (G_OBJECT_TYPE (object
) != SWFDEC_TYPE_AS_OBJECT
)
702 return g_strdup (G_OBJECT_TYPE_NAME (object
));
704 return g_strdup ("Object");
708 swfdec_as_object_constructor (GType type
, guint n_construct_properties
,
709 GObjectConstructParam
*construct_properties
)
712 SwfdecAsContext
*context
;
714 gobject
= G_OBJECT_CLASS (swfdec_as_object_parent_class
)->constructor (type
,
715 n_construct_properties
, construct_properties
);
717 context
= swfdec_gc_object_get_context (gobject
);
718 if (context
->debugger
) {
719 SwfdecAsDebuggerClass
*dklass
= SWFDEC_AS_DEBUGGER_GET_CLASS (context
->debugger
);
721 dklass
->add (context
->debugger
, context
, SWFDEC_AS_OBJECT (gobject
));
728 swfdec_as_object_class_init (SwfdecAsObjectClass
*klass
)
730 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
731 SwfdecGcObjectClass
*gc_class
= SWFDEC_GC_OBJECT_CLASS (klass
);
733 object_class
->constructor
= swfdec_as_object_constructor
;
734 object_class
->dispose
= swfdec_as_object_dispose
;
736 gc_class
->mark
= swfdec_as_object_mark
;
738 klass
->get
= swfdec_as_object_do_get
;
739 klass
->set
= swfdec_as_object_do_set
;
740 klass
->set_flags
= swfdec_as_object_do_set_flags
;
741 klass
->del
= swfdec_as_object_do_delete
;
742 klass
->foreach
= swfdec_as_object_do_foreach
;
743 klass
->debug
= swfdec_as_object_do_debug
;
747 swfdec_as_object_init (SwfdecAsObject
*object
)
749 object
->properties
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
753 * swfdec_as_object_new_empty:
754 * @context: a #SwfdecAsContext
756 * Creates an empty object. The prototype and constructor properties of the
757 * returned object will not be set. You probably want to call
758 * swfdec_as_object_set_constructor() on the returned object yourself.
759 * You may want to use swfdec_as_object_new() instead.
761 * Returns: A new #SwfdecAsObject added to @context
764 swfdec_as_object_new_empty (SwfdecAsContext
*context
)
766 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
768 return g_object_new (SWFDEC_TYPE_AS_OBJECT
, "context", context
, NULL
);
772 * swfdec_as_object_new:
773 * @context: a #SwfdecAsContext
775 * Allocates a new Object. This does the same as the Actionscript code
778 * Returns: the new object
781 swfdec_as_object_new (SwfdecAsContext
*context
)
783 SwfdecAsObject
*object
;
786 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), NULL
);
787 g_assert (context
->Object
);
788 g_assert (context
->Object_prototype
);
790 object
= swfdec_as_object_new_empty (context
);
791 SWFDEC_AS_VALUE_SET_OBJECT (&val
, context
->Object
);
792 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR_constructor
,
793 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
794 SWFDEC_AS_VALUE_SET_OBJECT (&val
, context
->Object_prototype
);
795 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR___proto__
,
796 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
801 * swfdec_as_object_set_variable:
802 * @object: a #SwfdecAsObject
803 * @variable: garbage-collected name of the variable to set
804 * @value: value to set the variable to
806 * Sets a variable on @object. It is not guaranteed that getting the variable
807 * after setting it results in the same value. This is a mcaro that calls
808 * swfdec_as_object_set_variable_and_flags()
811 * swfdec_as_object_set_variable_and_flags:
812 * @object: a #SwfdecAsObject
813 * @variable: garbage-collected name of the variable to set
814 * @value: value to set the variable to
815 * @default_flags: flags to use if creating the variable anew - the flags will
816 * be ignored if the property already exists.
818 * Sets a variable on @object. It is not guaranteed that getting the variable
819 * after setting it results in the same value, because various mechanisms (like
820 * the Actionscript Object.addProperty function or constant variables) can
824 swfdec_as_object_set_variable_and_flags (SwfdecAsObject
*object
,
825 const char *variable
, const SwfdecAsValue
*value
, guint default_flags
)
827 SwfdecAsObjectClass
*klass
;
829 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
830 g_return_if_fail (variable
!= NULL
);
831 g_return_if_fail (SWFDEC_IS_AS_VALUE (value
));
833 if (swfdec_gc_object_get_context (object
)->debugger
) {
834 SwfdecAsDebugger
*debugger
= swfdec_gc_object_get_context (object
)->debugger
;
835 SwfdecAsDebuggerClass
*dklass
= SWFDEC_AS_DEBUGGER_GET_CLASS (debugger
);
836 if (dklass
->set_variable
)
837 dklass
->set_variable (debugger
, swfdec_gc_object_get_context (object
), object
, variable
, value
);
839 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
840 klass
->set (object
, variable
, value
, default_flags
);
844 * swfdec_as_object_peek_variable:
845 * @object: the object to query
846 * @name: name of the variable to query
848 * Checks if the given @object contains a variable wih the given @name and if
849 * so, returns a pointer to its value. This pointer will be valid until calling
850 * a setting function on the given object again.
851 * <warning><para>This function is internal as it provides a pointer to an
852 * internal structure. Do not use it unless you are sure you need to. This
853 * function skips prototypes, variables added via swfdec_as_value_add_variable()
854 * and does not verify visibility flags.</para></warning>
856 * Returns: a pointer to the queried variable or %NULL if it doesn't exist
859 swfdec_as_object_peek_variable (SwfdecAsObject
*object
, const char *name
)
861 SwfdecAsVariable
*var
;
863 var
= swfdec_as_object_hash_lookup (object
, name
);
872 * swfdec_as_object_get_variable:
873 * @object: a #SwfdecAsObject
874 * @variable: a garbage-collected string containing the name of the variable
875 * @value: pointer to a #SwfdecAsValue that takes the return value or %NULL
877 * Gets the value of the given @variable on @object. It walks the prototype
878 * chain. This is a shortcut macro for
879 * swfdec_as_object_get_variable_and_flags().
881 * Returns: %TRUE if the variable existed, %FALSE otherwise
885 * swfdec_as_object_get_variable_and_flags:
886 * @object: a #SwfdecAsObject
887 * @variable: a garbage-collected string containing the name of the variable
888 * @value: pointer to a #SwfdecAsValue that takes the return value or %NULL
889 * @flags: pointer to a guint taking the variable's flags or %NULL
890 * @pobject: pointer to set to the object that really holds the property or
893 * Looks up @variable on @object. It also walks the object's prototype chain.
894 * If the variable exists, its value, flags and the real object containing the
895 * variable will be set and %TRUE will be returned.
897 * Returns: %TRUE if the variable exists, %FALSE otherwise
900 swfdec_as_object_get_variable_and_flags (SwfdecAsObject
*object
,
901 const char *variable
, SwfdecAsValue
*value
, guint
*flags
, SwfdecAsObject
**pobject
)
903 SwfdecAsObjectClass
*klass
;
905 SwfdecAsValue tmp_val
;
907 SwfdecAsObject
*tmp_pobject
, *cur
, *resolve
;
909 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
910 g_return_val_if_fail (variable
!= NULL
, FALSE
);
917 pobject
= &tmp_pobject
;
921 for (i
= 0; i
<= SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
&& cur
!= NULL
; i
++) {
922 klass
= SWFDEC_AS_OBJECT_GET_CLASS (cur
);
923 if (klass
->get (cur
, object
, variable
, value
, flags
)) {
927 if (resolve
== NULL
) {
928 SwfdecAsVariable
*var
=
929 swfdec_as_object_hash_lookup (cur
, SWFDEC_AS_STR___resolve
);
931 if (var
!= NULL
&& (swfdec_gc_object_get_context (object
)->version
<= 6 ||
932 SWFDEC_AS_VALUE_IS_OBJECT (&var
->value
)))
935 cur
= swfdec_as_object_get_prototype_internal (cur
);
937 if (i
> SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
) {
938 swfdec_as_context_abort (swfdec_gc_object_get_context (object
), "Prototype recursion limit exceeded");
939 SWFDEC_AS_VALUE_SET_UNDEFINED (value
);
944 if (variable
!= SWFDEC_AS_STR___resolve
&& resolve
!= NULL
) {
946 SwfdecAsVariable
*var
;
947 SwfdecAsFunction
*fun
;
948 SwfdecAsContext
*context
;
952 SWFDEC_AS_VALUE_SET_UNDEFINED (value
);
953 context
= swfdec_gc_object_get_context (resolve
);
955 var
= swfdec_as_object_hash_lookup (resolve
, SWFDEC_AS_STR___resolve
);
956 g_assert (var
!= NULL
);
957 if (!SWFDEC_AS_VALUE_IS_OBJECT (&var
->value
))
959 fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&var
->value
);
960 if (!SWFDEC_IS_AS_FUNCTION (fun
))
962 SWFDEC_AS_VALUE_SET_STRING (&argv
, variable
);
963 swfdec_as_function_call (fun
, resolve
, 1, &argv
, value
);
967 //SWFDEC_WARNING ("no such variable %s", variable);
968 SWFDEC_AS_VALUE_SET_UNDEFINED (value
);
975 * swfdec_as_object_has_variable:
976 * @object: a #SwfdecAsObject
977 * @variable: garbage-collected variable name
979 * Checks if a user-set @variable with the given name exists on @object. This
980 * function does not check variables that are available via an overwritten get
981 * function of the object's class.
983 * Returns: the object in the prototype chain that contains @variable or %NULL
984 * if the @object does not contain this variable.
987 swfdec_as_object_has_variable (SwfdecAsObject
*object
, const char *variable
)
990 SwfdecAsVariable
*var
;
992 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
994 for (i
= 0; i
<= SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
&& object
!= NULL
; i
++) {
995 var
= swfdec_as_object_hash_lookup (object
, variable
);
997 /* FIXME: propflags? */
1000 object
= swfdec_as_object_get_prototype_internal (object
);
1006 * swfdec_as_object_delete_variable:
1007 * @object: a #SwfdecAsObject
1008 * @variable: garbage-collected name of the variable
1010 * Deletes the given variable if possible. If the variable is protected from
1011 * deletion, it will not be deleted.
1013 * Returns: See #SwfdecAsDeleteReturn for details of the return value.
1015 SwfdecAsDeleteReturn
1016 swfdec_as_object_delete_variable (SwfdecAsObject
*object
, const char *variable
)
1018 SwfdecAsObjectClass
*klass
;
1020 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
1021 g_return_val_if_fail (variable
!= NULL
, FALSE
);
1023 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1024 return klass
->del (object
, variable
);
1028 * swfdec_as_object_delete_all_variables:
1029 * @object: a #SwfdecAsObject
1031 * Deletes all user-set variables from the given object.
1034 swfdec_as_object_delete_all_variables (SwfdecAsObject
*object
)
1036 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1038 g_hash_table_foreach (object
->properties
, swfdec_as_object_free_property
, object
);
1039 g_hash_table_remove_all (object
->properties
);
1043 * swfdec_as_object_set_variable_flags:
1044 * @object: a #SwfdecAsObject
1045 * @variable: the variable to modify
1046 * @flags: flags to set
1048 * Sets the given flags for the given variable.
1051 swfdec_as_object_set_variable_flags (SwfdecAsObject
*object
,
1052 const char *variable
, SwfdecAsVariableFlag flags
)
1054 SwfdecAsObjectClass
*klass
;
1056 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1057 g_return_if_fail (variable
!= NULL
);
1059 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1060 klass
->set_flags (object
, variable
, flags
, flags
);
1064 * swfdec_as_object_unset_variable_flags:
1065 * @object: a #SwfdecAsObject
1066 * @variable: the variable to modify
1067 * @flags: flags to unset
1069 * Unsets the given flags for the given variable. The variable must exist in
1073 swfdec_as_object_unset_variable_flags (SwfdecAsObject
*object
,
1074 const char *variable
, SwfdecAsVariableFlag flags
)
1076 SwfdecAsObjectClass
*klass
;
1078 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1079 g_return_if_fail (variable
!= NULL
);
1081 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1082 klass
->set_flags (object
, variable
, 0, flags
);
1086 * swfdec_as_object_foreach:
1087 * @object: a #SwfdecAsObject
1088 * @func: function to call
1089 * @data: data to pass to @func
1091 * Calls @func for every variable of @object or until @func returns %FALSE. The
1092 * variables of @object must not be modified by @func.
1094 * Returns: %TRUE if @func always returned %TRUE
1097 swfdec_as_object_foreach (SwfdecAsObject
*object
, SwfdecAsVariableForeach func
,
1100 SwfdecAsObjectClass
*klass
;
1102 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
1103 g_return_val_if_fail (func
!= NULL
, FALSE
);
1105 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1106 g_return_val_if_fail (klass
->foreach
!= NULL
, FALSE
);
1107 return klass
->foreach (object
, func
, data
);
1110 /*** SIMPLIFICATIONS ***/
1113 swfdec_as_object_do_nothing (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1114 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1119 * swfdec_as_object_add_function:
1120 * @object: a #SwfdecAsObject
1121 * @name: name of the function. The string does not have to be
1122 * garbage-collected.
1123 * @native: a native function or %NULL to just not do anything
1125 * Adds @native as a variable named @name to @object. The newly added variable
1126 * will not be enumerated.
1128 * Returns: the newly created #SwfdecAsFunction
1131 swfdec_as_object_add_function (SwfdecAsObject
*object
, const char *name
, SwfdecAsNative native
)
1133 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
1134 g_return_val_if_fail (name
!= NULL
, NULL
);
1136 return swfdec_as_object_add_constructor (object
, name
, 0, native
, NULL
);
1140 * swfdec_as_object_add_constructor:
1141 * @object: a #SwfdecAsObject
1142 * @name: name of the function. The string does not have to be
1143 * garbage-collected.
1144 * @construct_type: type used when using this function as a constructor. May
1145 * be 0 to use the default type.
1146 * @native: a native function or %NULL to just not do anything
1147 * @prototype: An optional object to be set as the "prototype" property of the
1148 * new function. The prototype will be hidden and constant.
1150 * Adds @native as a constructor named @name to @object. The newly added variable
1151 * will not be enumerated.
1153 * Returns: the newly created #SwfdecAsFunction
1156 swfdec_as_object_add_constructor (SwfdecAsObject
*object
, const char *name
,
1157 GType construct_type
, SwfdecAsNative native
, SwfdecAsObject
*prototype
)
1159 SwfdecAsFunction
*function
;
1162 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
1163 g_return_val_if_fail (name
!= NULL
, NULL
);
1164 g_return_val_if_fail (construct_type
== 0 || g_type_is_a (construct_type
, SWFDEC_TYPE_AS_OBJECT
), NULL
);
1165 g_return_val_if_fail (prototype
== NULL
|| SWFDEC_IS_AS_OBJECT (prototype
), NULL
);
1168 native
= swfdec_as_object_do_nothing
;
1169 function
= swfdec_as_native_function_new (swfdec_gc_object_get_context (object
), name
, native
, prototype
);
1170 if (construct_type
!= 0)
1171 swfdec_as_native_function_set_construct_type (SWFDEC_AS_NATIVE_FUNCTION (function
), construct_type
);
1172 name
= swfdec_as_context_get_string (swfdec_gc_object_get_context (object
), name
);
1173 SWFDEC_AS_VALUE_SET_OBJECT (&val
, SWFDEC_AS_OBJECT (function
));
1174 /* FIXME: I'd like to make sure no such property exists yet */
1175 swfdec_as_object_set_variable_and_flags (object
, name
, &val
,
1176 SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1181 * swfdec_as_object_run:
1182 * @object: a #SwfdecAsObject
1183 * @script: script to execute
1185 * Executes the given @script with @object as this pointer.
1188 swfdec_as_object_run (SwfdecAsObject
*object
, SwfdecScript
*script
)
1190 SwfdecAsFrame frame
= { NULL
, };
1191 SwfdecAsContext
*context
;
1193 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1194 g_return_if_fail (script
!= NULL
);
1196 context
= swfdec_gc_object_get_context (object
);
1197 swfdec_as_frame_init (&frame
, context
, script
);
1198 swfdec_as_frame_set_this (&frame
, object
);
1199 swfdec_as_frame_preload (&frame
);
1200 /* we take no prisoners */
1201 frame
.activation
= NULL
;
1202 swfdec_as_context_run (context
);
1203 swfdec_as_stack_pop (context
);
1207 * swfdec_as_object_call:
1208 * @object: a #SwfdecAsObject
1209 * @name: garbage-collected string naming the function to call.
1210 * @argc: number of arguments to provide to function
1211 * @argv: arguments or %NULL when @argc is 0
1212 * @return_value: location to take the return value of the call or %NULL to
1213 * ignore the return value.
1215 * Calls the function named @name on the given object. This function is
1216 * essentially equal to the folloeing Actionscript code:
1217 * <informalexample><programlisting>
1218 * @return_value = @object.@name (@argv[0], ..., @argv[argc-1]);
1219 * </programlisting></informalexample>
1221 * Returns: %TRUE if @object had a function with the given name, %FALSE otherwise
1224 swfdec_as_object_call (SwfdecAsObject
*object
, const char *name
, guint argc
,
1225 SwfdecAsValue
*argv
, SwfdecAsValue
*return_value
)
1228 SwfdecAsFunction
*fun
;
1230 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), TRUE
);
1231 g_return_val_if_fail (name
!= NULL
, TRUE
);
1232 g_return_val_if_fail (argc
== 0 || argv
!= NULL
, TRUE
);
1233 g_return_val_if_fail (swfdec_gc_object_get_context (object
)->global
!= NULL
, TRUE
); /* for SwfdecPlayer */
1236 SWFDEC_AS_VALUE_SET_UNDEFINED (return_value
);
1237 swfdec_as_object_get_variable (object
, name
, &tmp
);
1238 if (!SWFDEC_AS_VALUE_IS_OBJECT (&tmp
))
1240 fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&tmp
);
1241 if (!SWFDEC_IS_AS_FUNCTION (fun
))
1243 swfdec_as_function_call (fun
, object
, argc
, argv
, return_value
? return_value
: &tmp
);
1249 * swfdec_as_object_create:
1251 * @n_args: number of arguments
1252 * @args: arguments to pass to constructor
1253 * @return_value: pointer for return value or %NULL to push the return value to
1256 * Creates a new object for the given constructor and runs the constructor.
1259 swfdec_as_object_create (SwfdecAsFunction
*fun
, guint n_args
,
1260 const SwfdecAsValue
*args
, SwfdecAsValue
*return_value
)
1263 SwfdecAsObject
*new;
1264 SwfdecAsContext
*context
;
1265 SwfdecAsFunction
*cur
;
1269 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (fun
));
1271 // FIXME: The way we decide object's type is wrong
1272 // It seems to be actually possible to change the type inside a constructor
1273 // (many times) by changing this.__proto__.__constructor__ and calling super
1275 context
= swfdec_gc_object_get_context (fun
);
1279 if (SWFDEC_IS_AS_NATIVE_FUNCTION (cur
)) {
1280 SwfdecAsNativeFunction
*native
= SWFDEC_AS_NATIVE_FUNCTION (cur
);
1281 if (native
->construct_size
) {
1282 type
= native
->construct_type
;
1283 size
= native
->construct_size
;
1288 swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (cur
), SWFDEC_AS_STR_prototype
, &val
);
1289 if (SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1290 SwfdecAsObject
*proto
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1291 swfdec_as_object_get_variable (proto
, SWFDEC_AS_STR___constructor__
, &val
);
1292 if (SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1293 cur
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1294 if (SWFDEC_IS_AS_FUNCTION (cur
)) {
1300 } while (type
== 0 && cur
!= NULL
&& i
< SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT
);
1302 type
= SWFDEC_TYPE_AS_OBJECT
;
1303 size
= sizeof (SwfdecAsObject
);
1306 new = g_object_new (type
, "context", context
, NULL
);
1307 /* set initial variables */
1308 if (swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (fun
), SWFDEC_AS_STR_prototype
, &val
)) {
1309 swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR___proto__
,
1310 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1312 SWFDEC_AS_VALUE_SET_OBJECT (&val
, SWFDEC_AS_OBJECT (fun
));
1313 if (context
->version
< 7) {
1314 swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR_constructor
,
1315 &val
, SWFDEC_AS_VARIABLE_HIDDEN
);
1317 swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR___constructor__
,
1318 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_VERSION_6_UP
);
1320 swfdec_as_function_call_full (fun
, new, TRUE
, new->prototype
, n_args
, args
, return_value
);
1324 swfdec_as_object_set_constructor_by_name (SwfdecAsObject
*object
, const char *name
, ...)
1326 SwfdecAsContext
*context
;
1327 SwfdecAsObject
*cur
;
1331 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1332 g_return_if_fail (name
!= NULL
);
1334 context
= swfdec_gc_object_get_context (object
);
1335 va_start (args
, name
);
1336 cur
= context
->global
;
1338 if (!swfdec_as_object_get_variable (cur
, name
, &val
) ||
1339 !SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1340 SWFDEC_WARNING ("could not find constructor %s", name
);
1343 cur
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1344 name
= va_arg (args
, const char *);
1345 } while (name
!= NULL
);
1347 swfdec_as_object_set_constructor (object
, cur
);
1351 * swfdec_as_object_set_constructor:
1352 * @object: a #SwfdecAsObject
1353 * @construct: the constructor of @object
1355 * Sets the constructor variables for @object. Most objects get these
1356 * variables set automatically, but for objects you created yourself, you want
1357 * to call this function. This is essentially the same as the following script
1359 * |[ object.constructor = construct;
1360 * object.__proto__ = construct.prototype; ]|
1363 swfdec_as_object_set_constructor (SwfdecAsObject
*object
, SwfdecAsObject
*construct
)
1367 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1368 g_return_if_fail (SWFDEC_IS_AS_OBJECT (construct
));
1370 SWFDEC_AS_VALUE_SET_OBJECT (&val
, construct
);
1371 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR_constructor
,
1372 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1373 swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (construct
),
1374 SWFDEC_AS_STR_prototype
, &val
);
1375 if (SWFDEC_AS_VALUE_IS_OBJECT (&val
)) {
1376 SwfdecAsObject
*proto
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
1377 SWFDEC_AS_VALUE_SET_OBJECT (&val
, proto
);
1378 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR___proto__
,
1379 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1381 SWFDEC_WARNING ("constructor has no prototype, not setting any");
1386 * swfdec_as_object_add_variable:
1387 * @object: a #SwfdecAsObject
1388 * @variable: name of the variable
1389 * @get: getter function to call when reading the variable
1390 * @set: setter function to call when writing the variable or %NULL if read-only
1391 * @default_flags: flags to use if creating the variable anew - the flags will
1392 * be ignored if the property already exists.
1394 * Adds a variable to @object in the same way as the Actionscript code
1395 * "object.addProperty()" would do. Accessing the variable will from now on be
1396 * handled by calling the @get or @set functions. A previous value of the
1397 * variable or a previous call to this function will be overwritten.
1400 swfdec_as_object_add_variable (SwfdecAsObject
*object
, const char *variable
,
1401 SwfdecAsFunction
*get
, SwfdecAsFunction
*set
, guint default_flags
)
1403 SwfdecAsVariable
*var
;
1405 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1406 g_return_if_fail (variable
!= NULL
);
1407 g_return_if_fail (SWFDEC_IS_AS_FUNCTION (get
));
1408 g_return_if_fail (set
== NULL
|| SWFDEC_IS_AS_FUNCTION (set
));
1410 var
= swfdec_as_object_hash_lookup (object
, variable
);
1412 var
= swfdec_as_object_hash_create (object
, variable
, default_flags
);
1420 swfdec_as_object_add_native_variable (SwfdecAsObject
*object
,
1421 const char *variable
, SwfdecAsNative get
, SwfdecAsNative set
)
1423 SwfdecAsFunction
*get_func
, *set_func
;
1425 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1426 g_return_if_fail (variable
!= NULL
);
1427 g_return_if_fail (get
!= NULL
);
1430 swfdec_as_native_function_new (swfdec_gc_object_get_context (object
), variable
, get
, NULL
);
1431 if (get_func
== NULL
)
1436 swfdec_as_native_function_new (swfdec_gc_object_get_context (object
), variable
, set
, NULL
);
1441 swfdec_as_object_add_variable (object
, variable
, get_func
, set_func
, 0);
1446 SWFDEC_AS_NATIVE (101, 2, swfdec_as_object_addProperty
)
1448 swfdec_as_object_addProperty (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1449 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1451 SwfdecAsFunction
*get
, *set
;
1454 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1457 name
= swfdec_as_value_to_string (cx
, &argv
[0]);
1458 if (!SWFDEC_AS_VALUE_IS_OBJECT (&argv
[1]) ||
1459 !SWFDEC_IS_AS_FUNCTION ((get
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1]))))
1461 if (SWFDEC_AS_VALUE_IS_OBJECT (&argv
[2])) {
1462 set
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (&argv
[2]);
1463 if (!SWFDEC_IS_AS_FUNCTION (set
))
1465 } else if (SWFDEC_AS_VALUE_IS_NULL (&argv
[2])) {
1471 swfdec_as_object_add_variable (object
, name
, get
, set
, 0);
1472 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1475 SWFDEC_AS_NATIVE (101, 5, swfdec_as_object_hasOwnProperty
)
1477 swfdec_as_object_hasOwnProperty (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1478 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1480 SwfdecAsVariable
*var
;
1486 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1488 // return false even if no params
1492 name
= swfdec_as_value_to_string (swfdec_gc_object_get_context (object
), &argv
[0]);
1494 if (!(var
= swfdec_as_object_hash_lookup (object
, name
)))
1497 /* This functions only checks NOT 6 flag, and checks it on ALL VERSIONS */
1498 if (var
->flags
& SWFDEC_AS_VARIABLE_VERSION_NOT_6
)
1501 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1504 SWFDEC_AS_NATIVE (101, 7, swfdec_as_object_isPropertyEnumerable
)
1506 swfdec_as_object_isPropertyEnumerable (SwfdecAsContext
*cx
,
1507 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
1508 SwfdecAsValue
*retval
)
1510 SwfdecAsVariable
*var
;
1516 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1518 // return false even if no params
1522 name
= swfdec_as_value_to_string (swfdec_gc_object_get_context (object
), &argv
[0]);
1524 if (!(var
= swfdec_as_object_hash_lookup (object
, name
)))
1527 if (var
->flags
& SWFDEC_AS_VARIABLE_HIDDEN
)
1530 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1533 SWFDEC_AS_NATIVE (101, 6, swfdec_as_object_isPrototypeOf
)
1535 swfdec_as_object_isPrototypeOf (SwfdecAsContext
*cx
,
1536 SwfdecAsObject
*object
, guint argc
, SwfdecAsValue
*argv
,
1537 SwfdecAsValue
*retval
)
1539 SwfdecAsObject
*class;
1541 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1543 // return false even if no params
1547 class = swfdec_as_value_to_object (cx
, &argv
[0]);
1551 while ((class = swfdec_as_object_get_prototype (class)) != NULL
) {
1552 if (object
== class) {
1553 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1558 // not found, nothing to do
1561 SWFDEC_AS_NATIVE (101, 0, swfdec_as_object_watch
)
1563 swfdec_as_object_watch (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1564 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1566 SwfdecAsWatch
*watch
;
1569 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1574 name
= swfdec_as_value_to_string (cx
, &argv
[0]);
1576 if (!SWFDEC_AS_VALUE_IS_OBJECT (&argv
[1]))
1579 if (!SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1])))
1582 if (object
->watches
== NULL
) {
1583 object
->watches
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
1584 NULL
, (GDestroyNotify
) swfdec_as_watch_unref
);
1587 watch
= g_hash_table_lookup (object
->watches
, name
);
1589 if (watch
== NULL
) {
1590 watch
= swfdec_as_watch_new (SWFDEC_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1])));
1593 g_hash_table_insert (object
->watches
, (char *) name
, watch
);
1595 watch
->watch
= SWFDEC_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (&argv
[1]));
1599 watch
->watch_data
= argv
[2];
1601 SWFDEC_AS_VALUE_SET_UNDEFINED (&watch
->watch_data
);
1604 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1607 SWFDEC_AS_NATIVE (101, 1, swfdec_as_object_unwatch
)
1609 swfdec_as_object_unwatch (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1610 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1612 SwfdecAsVariable
*var
;
1618 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, FALSE
);
1623 name
= swfdec_as_value_to_string (cx
, &argv
[0]);
1625 // special case: can't unwatch native properties
1626 if ((var
= swfdec_as_object_hash_lookup (object
, name
))&& var
->get
!= NULL
)
1629 if (object
->watches
!= NULL
&&
1630 g_hash_table_remove (object
->watches
, name
)) {
1632 SWFDEC_AS_VALUE_SET_BOOLEAN (retval
, TRUE
);
1634 if (g_hash_table_size (object
->watches
) == 0) {
1635 g_hash_table_destroy (object
->watches
);
1636 object
->watches
= NULL
;
1641 SWFDEC_AS_NATIVE (101, 3, swfdec_as_object_valueOf
)
1643 swfdec_as_object_valueOf (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1644 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1647 SWFDEC_AS_VALUE_SET_OBJECT (retval
, object
);
1650 SWFDEC_AS_NATIVE (101, 4, swfdec_as_object_toString
)
1652 swfdec_as_object_toString (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1653 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*retval
)
1655 if (SWFDEC_IS_AS_FUNCTION (object
)) {
1656 SWFDEC_AS_VALUE_SET_STRING (retval
, SWFDEC_AS_STR__type_Function_
);
1658 SWFDEC_AS_VALUE_SET_STRING (retval
, SWFDEC_AS_STR__object_Object_
);
1662 // only available as ASnative
1663 SWFDEC_AS_NATIVE (3, 3, swfdec_as_object_old_constructor
)
1665 swfdec_as_object_old_constructor (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1666 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*ret
)
1668 SWFDEC_STUB ("old 'Object' function (only available as ASnative)");
1672 swfdec_as_object_decode (SwfdecAsObject
*object
, const char *str
)
1674 SwfdecAsContext
*cx
= swfdec_gc_object_get_context (object
);
1676 char **varlist
, *p
, *unescaped
;
1679 g_return_if_fail (SWFDEC_IS_AS_OBJECT (object
));
1680 g_return_if_fail (str
!= NULL
);
1682 varlist
= g_strsplit (str
, "&", -1);
1684 for (i
= 0; varlist
[i
] != NULL
; i
++) {
1685 p
= strchr (varlist
[i
], '=');
1693 unescaped
= swfdec_as_string_unescape (cx
, p
);
1694 if (unescaped
!= NULL
) {
1695 SWFDEC_AS_VALUE_SET_STRING (&val
,
1696 swfdec_as_context_give_string (cx
, unescaped
));
1698 SWFDEC_AS_VALUE_SET_STRING (&val
, SWFDEC_AS_STR_EMPTY
);
1701 SWFDEC_AS_VALUE_SET_STRING (&val
, SWFDEC_AS_STR_EMPTY
);
1703 unescaped
= swfdec_as_string_unescape (cx
, varlist
[i
]);
1704 if (unescaped
!= NULL
) {
1705 swfdec_as_object_set_variable (object
,
1706 swfdec_as_context_give_string (cx
, unescaped
), &val
);
1709 g_strfreev (varlist
);
1713 swfdec_as_object_construct (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
1714 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*ret
)
1717 SwfdecAsObject
*result
= swfdec_as_value_to_object (cx
, &argv
[0]);
1718 if (result
!= NULL
) {
1719 if (!cx
->frame
->construct
) {
1720 SWFDEC_AS_VALUE_SET_OBJECT (ret
, result
);
1722 SWFDEC_FIXME ("new Object (x) should return x");
1723 SWFDEC_AS_VALUE_SET_OBJECT (ret
, object
);
1729 if (!cx
->frame
->construct
)
1730 object
= swfdec_as_object_new_empty (cx
);
1732 SWFDEC_AS_VALUE_SET_OBJECT (ret
, object
);
1736 swfdec_as_object_init_context (SwfdecAsContext
*context
)
1739 SwfdecAsObject
*object
, *proto
;
1741 proto
= swfdec_as_object_new_empty (context
);
1742 object
= SWFDEC_AS_OBJECT (swfdec_as_object_add_function (context
->global
,
1743 SWFDEC_AS_STR_Object
, swfdec_as_object_construct
));
1744 context
->Object
= object
;
1745 context
->Object_prototype
= proto
;
1746 SWFDEC_AS_VALUE_SET_OBJECT (&val
, proto
);
1747 /* first, set our own */
1748 swfdec_as_object_set_variable_and_flags (object
, SWFDEC_AS_STR_prototype
,
1749 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
|
1750 SWFDEC_AS_VARIABLE_CONSTANT
);
1752 /* then finish the function prototype (use this order or
1753 * SWFDEC_AS_VARIABLE_CONSTANT won't let us */
1754 swfdec_as_object_set_variable_and_flags (context
->Function_prototype
,
1755 SWFDEC_AS_STR___proto__
, &val
,
1756 SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1758 SWFDEC_AS_VALUE_SET_OBJECT (&val
, object
);
1759 swfdec_as_object_set_variable_and_flags (proto
, SWFDEC_AS_STR_constructor
,
1760 &val
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
1764 * swfdec_as_object_get_debug:
1765 * @object: a #SwfdecAsObject
1767 * Gets a representation string suitable for debugging. This function is
1768 * guaranteed to not modify the state of the script engine, unlike
1769 * swfdec_as_value_to_string() for example.
1771 * Returns: A newly allocated string. Free it with g_free() after use.
1774 swfdec_as_object_get_debug (SwfdecAsObject
*object
)
1776 SwfdecAsObjectClass
*klass
;
1778 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
1780 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1781 return klass
->debug (object
);
1785 * swfdec_as_object_resolve:
1786 * @object: a #SwfdecAsObject
1788 * Resolves the object to its real object. Some internal objects should not be
1789 * exposed to scripts, for example #SwfdecAsFrame objects. If an object you want
1790 * to expose might be internal, call this function to resolve it to an object
1791 * that is safe to expose.
1793 * Returns: a non-internal object
1796 swfdec_as_object_resolve (SwfdecAsObject
*object
)
1798 SwfdecAsObjectClass
*klass
;
1800 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), NULL
);
1802 klass
= SWFDEC_AS_OBJECT_GET_CLASS (object
);
1803 if (klass
->resolve
== NULL
)
1806 return klass
->resolve (object
);