[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

Benjamin Otte company at kemper.freedesktop.org
Wed Nov 14 08:09:13 PST 2007


 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)


More information about the Swfdec mailing list