Benjamin Otte
2007-Nov-14 16:09 UTC
[Swfdec] 7 commits - libswfdec/swfdec_as_frame.c libswfdec/swfdec_as_function.c libswfdec/swfdec_as_internal.h libswfdec/swfdec_as_interpret.c libswfdec/swfdec_as_object.c libswfdec/swfdec_as_super.c libswfdec/swfdec_as_super.h
libswfdec/swfdec_as_frame.c | 3 - libswfdec/swfdec_as_function.c | 66 ++++++++++++++++-------- libswfdec/swfdec_as_internal.h | 16 ++++- libswfdec/swfdec_as_interpret.c | 60 +++++++++++----------- libswfdec/swfdec_as_object.c | 10 ++- libswfdec/swfdec_as_super.c | 109 +++++++++++++++++++++------------------- libswfdec/swfdec_as_super.h | 10 ++- 7 files changed, 159 insertions(+), 115 deletions(-) New commits: commit 9df5ed45ad9076f38f69903016298dc87b661efe Author: Benjamin Otte <otte at gnome.org> Date: Wed Nov 14 17:03:15 2007 +0100 work instantiating of super objects once again swfdec_as_super_new () now takes a this object and a reference object. Usually, the reference will be this->prototype, but in special cases, this is not true. diff --git a/libswfdec/swfdec_as_function.c b/libswfdec/swfdec_as_function.c index ef60c0b..c64df5e 100644 --- a/libswfdec/swfdec_as_function.c +++ b/libswfdec/swfdec_as_function.c @@ -164,10 +164,10 @@ swfdec_as_function_call (SwfdecAsFunction *function, SwfdecAsObject *thisp, guin if (frame == NULL) return; if (thisp != NULL) { - swfdec_as_super_new (frame, thisp, FALSE); + swfdec_as_super_new (frame, thisp, thisp->prototype); } else { SWFDEC_FIXME ("does the super object really reference the function when thisp is NULL?"); - swfdec_as_super_new (frame, SWFDEC_AS_OBJECT (function), FALSE); + swfdec_as_super_new (frame, SWFDEC_AS_OBJECT (function), SWFDEC_AS_OBJECT (function)->prototype); } swfdec_as_frame_preload (frame); } diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c index c911276..cb44953 100644 --- a/libswfdec/swfdec_as_interpret.c +++ b/libswfdec/swfdec_as_interpret.c @@ -876,6 +876,7 @@ swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data SwfdecAsFrame *frame = cx->frame; SwfdecAsValue *val; SwfdecAsObject *obj; + SwfdecAsObject *pobj = NULL; guint n_args; const char *name; @@ -892,7 +893,7 @@ swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data name = ""; } else { SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx, 3), obj); - swfdec_as_object_get_variable (obj, name, swfdec_as_stack_peek (cx, 2)); + swfdec_as_object_get_variable_and_flags (obj, name, swfdec_as_stack_peek (cx, 2), NULL, &pobj); } } else { if (SWFDEC_AS_VALUE_IS_STRING (val)) @@ -908,8 +909,10 @@ swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data /* setup super to point to the right prototype */ if (SWFDEC_IS_AS_SUPER (obj)) { swfdec_as_super_new_chain (frame, SWFDEC_AS_SUPER (obj), name); + } else if (cx->version > 6) { + swfdec_as_super_new (frame, obj, pobj == obj ? obj->prototype : pobj); } else { - swfdec_as_super_new (frame, obj, FALSE); + swfdec_as_super_new (frame, obj, obj->prototype); } swfdec_as_frame_preload (frame); } else { diff --git a/libswfdec/swfdec_as_object.c b/libswfdec/swfdec_as_object.c index 1127cef..9a723f4 100644 --- a/libswfdec/swfdec_as_object.c +++ b/libswfdec/swfdec_as_object.c @@ -1283,7 +1283,7 @@ swfdec_as_object_create (SwfdecAsFunction *fun, guint n_args, frame = swfdec_as_function_call_no_preload (fun, new, n_args, args, return_value); frame->construct = TRUE; - swfdec_as_super_new (frame, new, TRUE); + swfdec_as_super_new (frame, new, new->prototype); swfdec_as_frame_preload (frame); } diff --git a/libswfdec/swfdec_as_super.c b/libswfdec/swfdec_as_super.c index 1a4df38..9e67b40 100644 --- a/libswfdec/swfdec_as_super.c +++ b/libswfdec/swfdec_as_super.c @@ -43,8 +43,6 @@ swfdec_as_super_call (SwfdecAsFunction *function) SwfdecAsFunctionClass *klass; SwfdecAsFrame *frame; - //if (!super->callable) - // return NULL; if (super->object == NULL) { SWFDEC_WARNING ("super () called without an object."); return NULL; @@ -146,13 +144,14 @@ swfdec_as_super_init (SwfdecAsSuper *super) } void -swfdec_as_super_new (SwfdecAsFrame *frame, SwfdecAsObject *ref, gboolean callable) +swfdec_as_super_new (SwfdecAsFrame *frame, SwfdecAsObject *thisp, SwfdecAsObject *ref) { SwfdecAsContext *context; SwfdecAsSuper *super; g_return_if_fail (SWFDEC_IS_AS_FRAME (frame)); - g_return_if_fail (SWFDEC_IS_AS_OBJECT (ref)); + g_return_if_fail (SWFDEC_IS_AS_OBJECT (thisp)); + g_return_if_fail (ref == NULL || SWFDEC_IS_AS_OBJECT (ref)); if (frame->super != NULL) return; @@ -165,12 +164,11 @@ swfdec_as_super_new (SwfdecAsFrame *frame, SwfdecAsObject *ref, gboolean callabl super = g_object_new (SWFDEC_TYPE_AS_SUPER, NULL); frame->super = SWFDEC_AS_OBJECT (super); swfdec_as_object_add (SWFDEC_AS_OBJECT (super), context, sizeof (SwfdecAsSuper)); - super->thisp = ref; - super->callable = callable; + super->thisp = thisp; if (context->version <= 5) { super->object = NULL; } else { - super->object = ref->prototype; + super->object = ref; } } @@ -188,38 +186,32 @@ void swfdec_as_super_new_chain (SwfdecAsFrame *frame, SwfdecAsSuper *super, const char *function_name) { - SwfdecAsSuper *replace; + SwfdecAsObject *ref; SwfdecAsContext *context; + g_return_if_fail (SWFDEC_IS_AS_FRAME (frame)); g_return_if_fail (SWFDEC_IS_AS_SUPER (super)); if (frame->super != NULL) return; - - context = SWFDEC_AS_OBJECT (frame)->context; - if (!swfdec_as_context_use_mem (context, sizeof (SwfdecAsSuper))) + + if (super->object == NULL) return; - replace = g_object_new (SWFDEC_TYPE_AS_SUPER, NULL); - frame->super = SWFDEC_AS_OBJECT (replace); - swfdec_as_object_add (SWFDEC_AS_OBJECT (replace), context, sizeof (SwfdecAsSuper)); - if (super->object == NULL || super->object->prototype == NULL) { - replace->object = NULL; + ref = super->object->prototype; + if (ref == NULL) return; - } - replace->thisp = super->thisp; - replace->object = super->object->prototype; - replace->callable = super->callable; + context = SWFDEC_AS_OBJECT (frame)->context; if (function_name && context->version > 6) { /* skip prototypes to find the next one that has this function defined */ SwfdecAsObject *res; - if (swfdec_as_object_get_variable_and_flags (replace->object, - function_name, NULL, NULL, &res) && - replace->object != res) { - while (replace->object->prototype != res) { - replace->object = replace->object->prototype; - g_return_if_fail (replace->object); + if (swfdec_as_object_get_variable_and_flags (ref, + function_name, NULL, NULL, &res) && ref != res) { + while (ref->prototype != res) { + ref = ref->prototype; + g_return_if_fail (ref); } } } + swfdec_as_super_new (frame, super->thisp, ref); } diff --git a/libswfdec/swfdec_as_super.h b/libswfdec/swfdec_as_super.h index 2eaa1d7..ad082e9 100644 --- a/libswfdec/swfdec_as_super.h +++ b/libswfdec/swfdec_as_super.h @@ -38,9 +38,8 @@ typedef struct _SwfdecAsSuperClass SwfdecAsSuperClass; struct _SwfdecAsSuper { SwfdecAsFunction function; - gboolean callable; /* TRUE if this super object can be called */ SwfdecAsObject * thisp; /* object super was called on */ - SwfdecAsObject * object; /* current prototype we reference */ + SwfdecAsObject * object; /* current prototype we reference or NULL if none */ }; struct _SwfdecAsSuperClass { @@ -50,8 +49,8 @@ struct _SwfdecAsSuperClass { GType swfdec_as_super_get_type (void); void swfdec_as_super_new (SwfdecAsFrame * frame, - SwfdecAsObject * ref, - gboolean callable); + SwfdecAsObject * thisp, + SwfdecAsObject * ref); void swfdec_as_super_new_chain (SwfdecAsFrame * frame, SwfdecAsSuper * super, const char * function_name); commit 45d1aa5e5d55422409f47dd686a09d1e29f30099 Author: Benjamin Otte <otte at gnome.org> Date: Wed Nov 14 16:43:59 2007 +0100 make creating chained super objects work diff --git a/libswfdec/swfdec_as_super.c b/libswfdec/swfdec_as_super.c index 20a4f02..1a4df38 100644 --- a/libswfdec/swfdec_as_super.c +++ b/libswfdec/swfdec_as_super.c @@ -27,6 +27,7 @@ #include "swfdec_as_context.h" #include "swfdec_as_frame_internal.h" #include "swfdec_as_function.h" +#include "swfdec_as_internal.h" #include "swfdec_as_strings.h" #include "swfdec_debug.h" #include "swfdec_movie.h" @@ -42,6 +43,8 @@ swfdec_as_super_call (SwfdecAsFunction *function) SwfdecAsFunctionClass *klass; SwfdecAsFrame *frame; + //if (!super->callable) + // return NULL; if (super->object == NULL) { SWFDEC_WARNING ("super () called without an object."); return NULL; @@ -71,19 +74,28 @@ swfdec_as_super_get (SwfdecAsObject *object, SwfdecAsObject *orig, const char *variable, SwfdecAsValue *val, guint *flags) { SwfdecAsSuper *super = SWFDEC_AS_SUPER (object); + SwfdecAsObjectClass *klass; + SwfdecAsObject *cur; + guint i; if (super->object == NULL) { SWFDEC_WARNING ("super.%s () called without an object.", variable); return FALSE; } - if (super->object->prototype == NULL) { - SWFDEC_WARNING ("super.%s () called without a prototype.", variable); - return FALSE; + cur = super->object->prototype; + for (i = 0; i <= SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT && cur != NULL; i++) { + klass = SWFDEC_AS_OBJECT_GET_CLASS (cur); + /* FIXME: is the orig pointer correct? */ + if (klass->get (cur, super->object, variable, val, flags)) + return TRUE; + /* FIXME: need get_prototype_internal here? */ + cur = swfdec_as_object_get_prototype (cur); } - if (!swfdec_as_object_get_variable_and_flags (super->object->prototype, variable, val, NULL, NULL)) - return FALSE; + if (i > SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT) + swfdec_as_context_abort (object->context, "Prototype recursion limit exceeded"); + SWFDEC_AS_VALUE_SET_UNDEFINED (val); *flags = 0; - return TRUE; + return FALSE; } static void @@ -166,13 +178,11 @@ swfdec_as_super_new (SwfdecAsFrame *frame, SwfdecAsObject *ref, gboolean callabl * swfdec_as_super_new_chain: * @frame: the frame that is called * @super: the super object to chain from - * @function_name: garbage-collected name of the function that was called on - * @super or %NULL + * @chain_to: object to chain to. Must be in the prototype chain of @super. Or + * %NULL to just use the super object's prototype * - * This is an internal function used to replace the current frame's super object - * with the next one starting from @super. (FIXME: nice explanation!) So when - * super.foo () has been called, a new frame is constructed and after that this - * function is called with @super and "foo" as @function_name. + * This function creates a super object relative to the given @super object. It + * is only needed when calling functions on the @super object. **/ void swfdec_as_super_new_chain (SwfdecAsFrame *frame, SwfdecAsSuper *super, @@ -180,11 +190,12 @@ swfdec_as_super_new_chain (SwfdecAsFrame *frame, SwfdecAsSuper *super, { SwfdecAsSuper *replace; SwfdecAsContext *context; - + g_return_if_fail (SWFDEC_IS_AS_SUPER (super)); - /* should be the first call trying to set super */ - g_return_if_fail (frame->super == NULL); + if (frame->super != NULL) + return; + context = SWFDEC_AS_OBJECT (frame)->context; if (!swfdec_as_context_use_mem (context, sizeof (SwfdecAsSuper))) return; @@ -202,10 +213,13 @@ swfdec_as_super_new_chain (SwfdecAsFrame *frame, SwfdecAsSuper *super, /* skip prototypes to find the next one that has this function defined */ SwfdecAsObject *res; if (swfdec_as_object_get_variable_and_flags (replace->object, - function_name, NULL, NULL, &res) && - replace->object != res) { - while (replace->object->prototype != res) - replace->object = replace->object->prototype; + function_name, NULL, NULL, &res) && + replace->object != res) { + while (replace->object->prototype != res) { + replace->object = replace->object->prototype; + g_return_if_fail (replace->object); + } } } } + commit da82269a02a6e227cdb78be59da48d645c4f5b7a Author: Benjamin Otte <otte at gnome.org> Date: Wed Nov 14 16:43:49 2007 +0100 create a chained super object for function calls diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c index 99a1410..c911276 100644 --- a/libswfdec/swfdec_as_interpret.c +++ b/libswfdec/swfdec_as_interpret.c @@ -877,7 +877,7 @@ swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data SwfdecAsValue *val; SwfdecAsObject *obj; guint n_args; - const char *name = NULL; + const char *name; swfdec_as_stack_ensure_size (cx, 3); obj = swfdec_as_value_to_object (cx, swfdec_as_stack_peek (cx, 2)); @@ -906,7 +906,11 @@ swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data frame = swfdec_action_call (cx, n_args); if (frame) { /* setup super to point to the right prototype */ - swfdec_as_super_new (frame, obj, FALSE); + if (SWFDEC_IS_AS_SUPER (obj)) { + swfdec_as_super_new_chain (frame, SWFDEC_AS_SUPER (obj), name); + } else { + swfdec_as_super_new (frame, obj, FALSE); + } swfdec_as_frame_preload (frame); } else { SWFDEC_WARNING ("no function named \"%s\" on object %s", name, obj ? G_OBJECT_TYPE_NAME(obj) : "unknown"); commit 24519c4a837757ff3cf5c0791b62c3731f3f0329 Author: Benjamin Otte <otte at gnome.org> Date: Wed Nov 14 16:43:24 2007 +0100 export RECURSION_LIMIT definition diff --git a/libswfdec/swfdec_as_internal.h b/libswfdec/swfdec_as_internal.h index 68ff91b..13624c0 100644 --- a/libswfdec/swfdec_as_internal.h +++ b/libswfdec/swfdec_as_internal.h @@ -33,6 +33,7 @@ G_BEGIN_DECLS #define SWFDEC_AS_CONSTRUCTOR(x, y, func, type) void func (SwfdecAsContext *cx, \ SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret); +#define SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT 256 void swfdec_as_function_set_constructor (SwfdecAsFunction * fun); void swfdec_as_function_set_security (SwfdecAsFunction * fun, diff --git a/libswfdec/swfdec_as_object.c b/libswfdec/swfdec_as_object.c index 3835a59..1127cef 100644 --- a/libswfdec/swfdec_as_object.c +++ b/libswfdec/swfdec_as_object.c @@ -36,8 +36,6 @@ #include "swfdec_movie.h" #include "swfdec_security_allow.h" -#define SWFDEC_AS_OBJECT_PROTOTYPE_RECURSION_LIMIT 256 - /** * SECTION:SwfdecAsObject * @title: SwfdecAsObject commit f215db2740e23b51fc3ec46d562c8fb611f796b6 Author: Benjamin Otte <otte at gnome.org> Date: Wed Nov 14 14:58:31 2007 +0100 rework super handling yet again This doesn't work properly yet, but small(ish) commits are better than lots of big ones. diff --git a/libswfdec/swfdec_as_function.c b/libswfdec/swfdec_as_function.c index fea1b3d..ef60c0b 100644 --- a/libswfdec/swfdec_as_function.c +++ b/libswfdec/swfdec_as_function.c @@ -118,14 +118,17 @@ swfdec_as_function_call_no_preload (SwfdecAsFunction *function, klass = SWFDEC_AS_FUNCTION_GET_CLASS (function); g_assert (klass->call); frame = klass->call (function); - /* FIXME: figure out what to do in these situations */ + /* FIXME: figure out what to do in these situations? + * It's a problem when called inside swfdec_as_function_call () as the + * user of that function expects success, but super may fail here */ if (frame == NULL) return NULL; if (function->priv) swfdec_as_frame_set_security (frame, function->priv); /* second check especially for super object */ - if (thisp != NULL && frame->thisp == NULL) + if (thisp != NULL && frame->thisp == NULL) { swfdec_as_frame_set_this (frame, swfdec_as_object_resolve (thisp)); + } frame->is_local = TRUE; frame->argc = n_args; frame->argv = args; @@ -160,7 +163,12 @@ swfdec_as_function_call (SwfdecAsFunction *function, SwfdecAsObject *thisp, guin frame = swfdec_as_function_call_no_preload (function, thisp, n_args, args, return_value); if (frame == NULL) return; - frame->super = swfdec_as_super_new (frame); + if (thisp != NULL) { + swfdec_as_super_new (frame, thisp, FALSE); + } else { + SWFDEC_FIXME ("does the super object really reference the function when thisp is NULL?"); + swfdec_as_super_new (frame, SWFDEC_AS_OBJECT (function), FALSE); + } swfdec_as_frame_preload (frame); } diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c index 613f594..99a1410 100644 --- a/libswfdec/swfdec_as_interpret.c +++ b/libswfdec/swfdec_as_interpret.c @@ -26,6 +26,7 @@ #include "swfdec_as_context.h" #include "swfdec_as_frame_internal.h" #include "swfdec_as_function.h" +#include "swfdec_as_internal.h" #include "swfdec_as_script_function.h" #include "swfdec_as_stack.h" #include "swfdec_as_string.h" @@ -801,9 +802,10 @@ swfdec_action_trace (SwfdecAsContext *cx, guint action, const guint8 *data, guin /* stack looks like this: [ function, this, arg1, arg2, ... ] */ /* stack must be at least 2 elements big */ -static gboolean +static SwfdecAsFrame * swfdec_action_call (SwfdecAsContext *cx, guint n_args) { + SwfdecAsFrame *frame; SwfdecAsFunction *fun; SwfdecAsObject *thisp; @@ -821,12 +823,14 @@ swfdec_action_call (SwfdecAsContext *cx, guint n_args) /* sanitize argument count */ if (n_args >= swfdec_as_stack_get_size (cx)) n_args = swfdec_as_stack_get_size (cx); - swfdec_as_function_call (fun, thisp, n_args, NULL, NULL); + frame = swfdec_as_function_call_no_preload (fun, thisp, n_args, NULL, NULL); + if (frame == NULL) + return NULL; if (SWFDEC_IS_AS_SUPER (fun)) { SWFDEC_LOG ("replacing super object on frame"); - swfdec_as_super_replace (SWFDEC_AS_SUPER (fun), NULL); + swfdec_as_super_new_chain (frame, SWFDEC_AS_SUPER (fun), NULL); } - return TRUE; + return frame; error: n_args += 2; @@ -834,7 +838,7 @@ error: n_args = swfdec_as_stack_get_size (cx); swfdec_as_stack_pop_n (cx, n_args); SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx)); - return FALSE; + return NULL; } static void @@ -858,7 +862,10 @@ swfdec_action_call_function (SwfdecAsContext *cx, guint action, const guint8 *da SWFDEC_AS_VALUE_SET_NULL (thisp); SWFDEC_AS_VALUE_SET_UNDEFINED (fun); } - if (!swfdec_action_call (cx, n_args)) { + frame = swfdec_action_call (cx, n_args); + if (frame) { + swfdec_as_frame_preload (frame); + } else { SWFDEC_WARNING ("no function named %s", name); } } @@ -876,45 +883,33 @@ swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data obj = swfdec_as_value_to_object (cx, swfdec_as_stack_peek (cx, 2)); n_args = swfdec_as_value_to_integer (cx, swfdec_as_stack_peek (cx, 3)); val = swfdec_as_stack_peek (cx, 1); - /* FIXME: this is a hack for constructors calling super - is this correct? */ - if (SWFDEC_AS_VALUE_IS_UNDEFINED (val)) { - SWFDEC_AS_VALUE_SET_STRING (val, SWFDEC_AS_STR_EMPTY); - } if (obj) { - if (SWFDEC_AS_VALUE_IS_STRING (val) && - SWFDEC_AS_VALUE_GET_STRING (val) == SWFDEC_AS_STR_EMPTY) { + name = swfdec_as_value_to_string (cx, val); + if (SWFDEC_AS_VALUE_IS_UNDEFINED (val) || + name == SWFDEC_AS_STR_EMPTY) { SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx, 3)); SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx, 2), obj); + name = ""; } else { SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx, 3), obj); - name = swfdec_as_value_to_string (cx, val); swfdec_as_object_get_variable (obj, name, swfdec_as_stack_peek (cx, 2)); } } else { if (SWFDEC_AS_VALUE_IS_STRING (val)) name = SWFDEC_AS_VALUE_GET_STRING (val); + else + name = "???"; SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_peek (cx, 3)); SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx, 2)); } swfdec_as_stack_pop (cx); - if (swfdec_action_call (cx, n_args)) { + frame = swfdec_action_call (cx, n_args); + if (frame) { /* setup super to point to the right prototype */ - frame = cx->frame; - if (SWFDEC_IS_AS_SUPER (obj)) { - swfdec_as_super_replace (SWFDEC_AS_SUPER (obj), name); - } else if (frame->super) { - SwfdecAsSuper *super = SWFDEC_AS_SUPER (frame->super); - if (name && - cx->version > 6 && - swfdec_as_object_get_variable_and_flags (frame->thisp, - name, NULL, NULL, &super->object) && - super->object == frame->thisp) { - // FIXME: Do we need to check prototype_flags here? - super->object = super->object->prototype; - } - } + swfdec_as_super_new (frame, obj, FALSE); + swfdec_as_frame_preload (frame); } else { - SWFDEC_WARNING ("no function named %s on object %s", name ? name : "unknown", obj ? G_OBJECT_TYPE_NAME(obj) : "unknown"); + SWFDEC_WARNING ("no function named \"%s\" on object %s", name, obj ? G_OBJECT_TYPE_NAME(obj) : "unknown"); } } diff --git a/libswfdec/swfdec_as_object.c b/libswfdec/swfdec_as_object.c index 5cc446c..3835a59 100644 --- a/libswfdec/swfdec_as_object.c +++ b/libswfdec/swfdec_as_object.c @@ -31,6 +31,7 @@ #include "swfdec_as_stack.h" #include "swfdec_as_string.h" #include "swfdec_as_strings.h" +#include "swfdec_as_super.h" #include "swfdec_debug.h" #include "swfdec_movie.h" #include "swfdec_security_allow.h" @@ -1230,6 +1231,7 @@ swfdec_as_object_create (SwfdecAsFunction *fun, guint n_args, SwfdecAsObject *new; SwfdecAsContext *context; SwfdecAsFunction *cur; + SwfdecAsFrame *frame; guint size; GType type = 0; @@ -1281,8 +1283,10 @@ swfdec_as_object_create (SwfdecAsFunction *fun, guint n_args, swfdec_as_object_set_variable_and_flags (new, SWFDEC_AS_STR___constructor__, &val, SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_VERSION_6_UP); - swfdec_as_function_call (fun, new, n_args, args, return_value); - context->frame->construct = TRUE; + frame = swfdec_as_function_call_no_preload (fun, new, n_args, args, return_value); + frame->construct = TRUE; + swfdec_as_super_new (frame, new, TRUE); + swfdec_as_frame_preload (frame); } /** diff --git a/libswfdec/swfdec_as_super.c b/libswfdec/swfdec_as_super.c index 3a52c16..20a4f02 100644 --- a/libswfdec/swfdec_as_super.c +++ b/libswfdec/swfdec_as_super.c @@ -133,41 +133,39 @@ swfdec_as_super_init (SwfdecAsSuper *super) { } -SwfdecAsObject * -swfdec_as_super_new (SwfdecAsFrame *frame) +void +swfdec_as_super_new (SwfdecAsFrame *frame, SwfdecAsObject *ref, gboolean callable) { SwfdecAsContext *context; SwfdecAsSuper *super; - SwfdecAsObject *ret; - g_return_val_if_fail (SWFDEC_IS_AS_FRAME (frame), NULL); + g_return_if_fail (SWFDEC_IS_AS_FRAME (frame)); + g_return_if_fail (SWFDEC_IS_AS_OBJECT (ref)); - if (frame->thisp == NULL) { - SWFDEC_FIXME ("found a case where this was NULL, test how super behaves here!"); - return NULL; - } - + if (frame->super != NULL) + return; context = SWFDEC_AS_OBJECT (frame)->context; - if (context->version <= 5 && !frame->construct) - return NULL; + if (context->version <= 5) + return; if (!swfdec_as_context_use_mem (context, sizeof (SwfdecAsSuper))) - return NULL; - ret = g_object_new (SWFDEC_TYPE_AS_SUPER, NULL); - swfdec_as_object_add (ret, context, sizeof (SwfdecAsSuper)); - super = SWFDEC_AS_SUPER (ret); - super->thisp = frame->thisp; + return; + super = g_object_new (SWFDEC_TYPE_AS_SUPER, NULL); + frame->super = SWFDEC_AS_OBJECT (super); + swfdec_as_object_add (SWFDEC_AS_OBJECT (super), context, sizeof (SwfdecAsSuper)); + super->thisp = ref; + super->callable = callable; if (context->version <= 5) { super->object = NULL; } else { - super->object = frame->thisp->prototype; + super->object = ref->prototype; } - return ret; } /** - * swfdec_as_super_replace: - * @super: the super object to replace from + * swfdec_as_super_new_chain: + * @frame: the frame that is called + * @super: the super object to chain from * @function_name: garbage-collected name of the function that was called on * @super or %NULL * @@ -177,23 +175,31 @@ swfdec_as_super_new (SwfdecAsFrame *frame) * function is called with @super and "foo" as @function_name. **/ void -swfdec_as_super_replace (SwfdecAsSuper *super, const char *function_name) +swfdec_as_super_new_chain (SwfdecAsFrame *frame, SwfdecAsSuper *super, + const char *function_name) { SwfdecAsSuper *replace; SwfdecAsContext *context; g_return_if_fail (SWFDEC_IS_AS_SUPER (super)); + /* should be the first call trying to set super */ + g_return_if_fail (frame->super == NULL); - context = SWFDEC_AS_OBJECT (super)->context; - replace = SWFDEC_AS_SUPER (context->frame->super); - if (replace == NULL) + context = SWFDEC_AS_OBJECT (frame)->context; + if (!swfdec_as_context_use_mem (context, sizeof (SwfdecAsSuper))) return; + replace = g_object_new (SWFDEC_TYPE_AS_SUPER, NULL); + frame->super = SWFDEC_AS_OBJECT (replace); + swfdec_as_object_add (SWFDEC_AS_OBJECT (replace), context, sizeof (SwfdecAsSuper)); if (super->object == NULL || super->object->prototype == NULL) { replace->object = NULL; return; } + replace->thisp = super->thisp; replace->object = super->object->prototype; + replace->callable = super->callable; if (function_name && context->version > 6) { + /* skip prototypes to find the next one that has this function defined */ SwfdecAsObject *res; if (swfdec_as_object_get_variable_and_flags (replace->object, function_name, NULL, NULL, &res) && diff --git a/libswfdec/swfdec_as_super.h b/libswfdec/swfdec_as_super.h index de14152..2eaa1d7 100644 --- a/libswfdec/swfdec_as_super.h +++ b/libswfdec/swfdec_as_super.h @@ -38,6 +38,7 @@ typedef struct _SwfdecAsSuperClass SwfdecAsSuperClass; struct _SwfdecAsSuper { SwfdecAsFunction function; + gboolean callable; /* TRUE if this super object can be called */ SwfdecAsObject * thisp; /* object super was called on */ SwfdecAsObject * object; /* current prototype we reference */ }; @@ -48,9 +49,11 @@ struct _SwfdecAsSuperClass { GType swfdec_as_super_get_type (void); -SwfdecAsObject *swfdec_as_super_new (SwfdecAsFrame * frame); - -void swfdec_as_super_replace (SwfdecAsSuper * super, +void swfdec_as_super_new (SwfdecAsFrame * frame, + SwfdecAsObject * ref, + gboolean callable); +void swfdec_as_super_new_chain (SwfdecAsFrame * frame, + SwfdecAsSuper * super, const char * function_name); G_END_DECLS commit c5b4397d7a2d1c915f55bc2c6864a79d11dcc199 Author: Benjamin Otte <otte at gnome.org> Date: Tue Nov 13 23:50:31 2007 +0100 add swfdec_as_function_call_no_preload () to allow doing stuff before preloading use this by swfdec_as_function_call () to create the super object. And don't create the super object in swfdec_as_frame_preload () anymore. It seems existance of a super object depends on how a function was called, so we need to make creation non-automatic. Currently, various tests will break. diff --git a/libswfdec/swfdec_as_frame.c b/libswfdec/swfdec_as_frame.c index e850d96..77f4c3a 100644 --- a/libswfdec/swfdec_as_frame.c +++ b/libswfdec/swfdec_as_frame.c @@ -699,9 +699,6 @@ swfdec_as_frame_preload (SwfdecAsFrame *frame) /* silence gcc */ args = NULL; } - if ((script->flags & (SWFDEC_SCRIPT_PRELOAD_SUPER | SWFDEC_SCRIPT_SUPPRESS_SUPER)) != SWFDEC_SCRIPT_SUPPRESS_SUPER) { - frame->super = swfdec_as_super_new (frame); - } /* set the default variables (unless suppressed */ if (!(script->flags & SWFDEC_SCRIPT_SUPPRESS_THIS)) { diff --git a/libswfdec/swfdec_as_function.c b/libswfdec/swfdec_as_function.c index 8d2f927..fea1b3d 100644 --- a/libswfdec/swfdec_as_function.c +++ b/libswfdec/swfdec_as_function.c @@ -26,6 +26,7 @@ #include "swfdec_as_frame_internal.h" #include "swfdec_as_internal.h" #include "swfdec_as_stack.h" +#include "swfdec_as_super.h" #include "swfdec_as_strings.h" #include "swfdec_debug.h" @@ -97,6 +98,41 @@ swfdec_as_function_set_constructor (SwfdecAsFunction *fun) SWFDEC_AS_VARIABLE_VERSION_6_UP); } +SwfdecAsFrame * +swfdec_as_function_call_no_preload (SwfdecAsFunction *function, + SwfdecAsObject *thisp, guint n_args, const SwfdecAsValue *args, + SwfdecAsValue *return_value) +{ + SwfdecAsContext *context; + SwfdecAsFrame *frame; + SwfdecAsFunctionClass *klass; + + g_return_val_if_fail (SWFDEC_IS_AS_FUNCTION (function), NULL); + g_return_val_if_fail (thisp == NULL || SWFDEC_IS_AS_OBJECT (thisp), NULL); + + context = SWFDEC_AS_OBJECT (function)->context; + /* just to be sure... */ + if (return_value) + SWFDEC_AS_VALUE_SET_UNDEFINED (return_value); + + klass = SWFDEC_AS_FUNCTION_GET_CLASS (function); + g_assert (klass->call); + frame = klass->call (function); + /* FIXME: figure out what to do in these situations */ + if (frame == NULL) + return NULL; + if (function->priv) + swfdec_as_frame_set_security (frame, function->priv); + /* second check especially for super object */ + if (thisp != NULL && frame->thisp == NULL) + swfdec_as_frame_set_this (frame, swfdec_as_object_resolve (thisp)); + frame->is_local = TRUE; + frame->argc = n_args; + frame->argv = args; + frame->return_value = return_value; + return frame; +} + /** * swfdec_as_function_call: * @function: the #SwfdecAsFunction to call @@ -116,33 +152,15 @@ void swfdec_as_function_call (SwfdecAsFunction *function, SwfdecAsObject *thisp, guint n_args, const SwfdecAsValue *args, SwfdecAsValue *return_value) { - SwfdecAsContext *context; SwfdecAsFrame *frame; - SwfdecAsFunctionClass *klass; g_return_if_fail (SWFDEC_IS_AS_FUNCTION (function)); g_return_if_fail (thisp == NULL || SWFDEC_IS_AS_OBJECT (thisp)); - context = SWFDEC_AS_OBJECT (function)->context; - /* just to be sure... */ - if (return_value) - SWFDEC_AS_VALUE_SET_UNDEFINED (return_value); - - klass = SWFDEC_AS_FUNCTION_GET_CLASS (function); - g_assert (klass->call); - frame = klass->call (function); - /* FIXME: figure out what to do in these situations */ + frame = swfdec_as_function_call_no_preload (function, thisp, n_args, args, return_value); if (frame == NULL) return; - if (function->priv) - swfdec_as_frame_set_security (frame, function->priv); - /* second check especially for super object */ - if (thisp != NULL && frame->thisp == NULL) - swfdec_as_frame_set_this (frame, swfdec_as_object_resolve (thisp)); - frame->is_local = TRUE; - frame->argc = n_args; - frame->argv = args; - frame->return_value = return_value; + frame->super = swfdec_as_super_new (frame); swfdec_as_frame_preload (frame); } diff --git a/libswfdec/swfdec_as_internal.h b/libswfdec/swfdec_as_internal.h index 6dc088d..68ff91b 100644 --- a/libswfdec/swfdec_as_internal.h +++ b/libswfdec/swfdec_as_internal.h @@ -34,11 +34,16 @@ G_BEGIN_DECLS SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret); -void swfdec_as_function_set_constructor (SwfdecAsFunction * fun); -void swfdec_as_function_set_security (SwfdecAsFunction * fun, - SwfdecSecurity * sec); -void swfdec_as_function_init_context (SwfdecAsContext * context, - guint version); +void swfdec_as_function_set_constructor (SwfdecAsFunction * fun); +void swfdec_as_function_set_security (SwfdecAsFunction * fun, + SwfdecSecurity * sec); +void swfdec_as_function_init_context (SwfdecAsContext * context, + guint version); +SwfdecAsFrame * swfdec_as_function_call_no_preload (SwfdecAsFunction * function, + SwfdecAsObject * thisp, + guint n_args, + const SwfdecAsValue * args, + SwfdecAsValue * return_value); /* swfdec_as_context.c */ gboolean swfdec_as_context_check_continue (SwfdecAsContext * context); commit 0fcd2465a6e039c65d749a761d31f699811b4692 Author: Benjamin Otte <otte at gnome.org> Date: Tue Nov 13 23:48:03 2007 +0100 movies _do_ get a super object diff --git a/libswfdec/swfdec_as_super.c b/libswfdec/swfdec_as_super.c index 8a94749..3a52c16 100644 --- a/libswfdec/swfdec_as_super.c +++ b/libswfdec/swfdec_as_super.c @@ -146,9 +146,6 @@ swfdec_as_super_new (SwfdecAsFrame *frame) SWFDEC_FIXME ("found a case where this was NULL, test how super behaves here!"); return NULL; } - /* functions called on native objects don't get a super object?! */ - if (SWFDEC_IS_MOVIE (frame->thisp)) - return NULL; context = SWFDEC_AS_OBJECT (frame)->context; if (context->version <= 5 && !frame->construct)
Possibly Parallel Threads
- Branch 'as' - 9 commits - libswfdec/swfdec_as_frame.c libswfdec/swfdec_as_function.c libswfdec/swfdec_as_function.h libswfdec/swfdec_as_interpret.c libswfdec/swfdec_as_native_function.c libswfdec/swfdec_as_object.c libswfdec/swfdec_as_script_function.c
- Branch 'as' - 11 commits - libswfdec/swfdec_as_array.c libswfdec/swfdec_as_context.c libswfdec/swfdec_as_function.c libswfdec/swfdec_as_interpret.c libswfdec/swfdec_as_native_function.c libswfdec/swfdec_as_number.c libswfdec/swfdec_as_object.c
- Branch 'as' - 7 commits - libswfdec/swfdec_as_context.c libswfdec/swfdec_as_interpret.c libswfdec/swfdec_as_object.c libswfdec/swfdec_as_object.h libswfdec/swfdec_as_super.c libswfdec/swfdec_as_super.h libswfdec/swfdec_as_with.c test/trace
- Branch 'as' - 25 commits - libswfdec/Makefile.am libswfdec/swfdec_as_boolean.c libswfdec/swfdec_as_boolean.h libswfdec/swfdec_as_context.c libswfdec/swfdec_as_context.h libswfdec/swfdec_as_frame.c libswfdec/swfdec_as_frame.h libswfdec/swfdec_as_function.c
- 10 commits - libswfdec/swfdec_as_frame.c libswfdec/swfdec_as_interpret.c libswfdec/swfdec_as_super.c libswfdec/swfdec_video_movie_as.c test/trace