[Swfdec] 3 commits - libswfdec/swfdec_as_context.c libswfdec/swfdec_as_context.h libswfdec/swfdec_as_interpret.c

Pekka Lampila medar at kemper.freedesktop.org
Fri Oct 26 14:27:30 PDT 2007


 libswfdec/swfdec_as_context.c   |   11 +
 libswfdec/swfdec_as_context.h   |    2 
 libswfdec/swfdec_as_interpret.c |  228 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 238 insertions(+), 3 deletions(-)

New commits:
commit a599de99164b86347df25cd615d6287487878c3e
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Sat Oct 27 00:26:04 2007 +0300

    Add some comments to Try code and make sure try_data gets freed properly

diff --git a/libswfdec/swfdec_as_context.c b/libswfdec/swfdec_as_context.c
index 25ee0f1..6e35622 100644
--- a/libswfdec/swfdec_as_context.c
+++ b/libswfdec/swfdec_as_context.c
@@ -809,6 +809,8 @@ start:
   check_block = TRUE;
 
   while (context->state < SWFDEC_AS_CONTEXT_ABORTED) {
+    // in case of an exception, skip blocks until exception is cleared or we
+    // run out of blocks
     while (context->throwing && frame->blocks->len > 0) {
       frame->pc = frame->block_end;
       swfdec_as_frame_check_block (frame);
diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c
index 3ab6fc0..cf41ff0 100644
--- a/libswfdec/swfdec_as_interpret.c
+++ b/libswfdec/swfdec_as_interpret.c
@@ -2543,6 +2543,7 @@ swfdec_action_throw (SwfdecAsContext *cx, guint action, const guint8 *data,
 }
 
 typedef struct {
+  int			ref_count;
   const guint8 *	start;
   gboolean		catch;
   gboolean		finally;
@@ -2557,10 +2558,25 @@ typedef struct {
 } TryData;
 
 static void
-swfdec_action_try_free_data (TryData *try_data)
+swfdec_action_try_data_ref (gpointer data)
 {
+  TryData *try_data = data;
+
+  g_return_if_fail (try_data != NULL);
+
+  try_data->ref_count++;
+}
+
+static void
+swfdec_action_try_data_unref (gpointer data)
+{
+  TryData *try_data = data;
+
   g_return_if_fail (try_data != NULL);
 
+  if (--try_data->ref_count > 0)
+    return;
+
   if (!try_data->use_register)
     g_free (try_data->variable_name);
   g_free (try_data);
@@ -2575,14 +2591,15 @@ swfdec_action_try_end_finally (SwfdecAsFrame *frame, gpointer data)
   g_return_if_fail (SWFDEC_IS_AS_FRAME (frame));
   g_return_if_fail (SWFDEC_IS_AS_VALUE (error));
 
-  swfdec_as_frame_pop_block (frame);
-
   cx = SWFDEC_AS_OBJECT (frame)->context;
 
+  // finally has ended and we had exception stored, throw it
   if (!cx->throwing) {
     cx->throwing = TRUE;
     cx->throw_value = *error;
   }
+
+  swfdec_as_frame_pop_block (frame);
 }
 
 static void
@@ -2597,9 +2614,15 @@ swfdec_action_try_end_catch (SwfdecAsFrame *frame, gpointer data)
 
   cx = SWFDEC_AS_OBJECT (frame)->context;
 
+  swfdec_action_try_data_ref (try_data);
   swfdec_as_frame_pop_block (frame);
 
-  if (cx->throwing) {
+  if (cx->throwing)
+  {
+    // we got an exception while in catch block:
+    // create new block for finally, passing the exception
+    // clear exception from the context
+
     error = g_malloc (sizeof (SwfdecAsValue));
     *error = cx->throw_value;
 
@@ -2611,7 +2634,7 @@ swfdec_action_try_end_catch (SwfdecAsFrame *frame, gpointer data)
     SWFDEC_AS_VALUE_SET_UNDEFINED (&cx->throw_value);
   }
 
-  swfdec_action_try_free_data (try_data);
+  swfdec_action_try_data_unref (try_data);
 }
 
 static void
@@ -2623,6 +2646,8 @@ swfdec_action_try_end_try (SwfdecAsFrame *frame, gpointer data)
   g_return_if_fail (SWFDEC_IS_AS_FRAME (frame));
   g_return_if_fail (try_data != NULL);
 
+  // if we don't have a catch block, we handle try block exactly like it was
+  // catch block
   if (!try_data->catch) {
     swfdec_action_try_end_catch (frame, try_data);
     return;
@@ -2630,19 +2655,26 @@ swfdec_action_try_end_try (SwfdecAsFrame *frame, gpointer data)
 
   cx = SWFDEC_AS_OBJECT (frame)->context;
 
+  swfdec_action_try_data_ref (try_data);
   swfdec_as_frame_pop_block (frame);
 
-  if (!cx->throwing) {
-    swfdec_action_try_free_data (try_data);
-  } else {
-    if (try_data->use_register) {
+  if (cx->throwing)
+  {
+    // we got an exception while in try block:
+    // set the error variable
+    // add new block for catch
+    // clear exception from context
+    if (try_data->use_register)
+    {
       if (swfdec_action_has_register (cx, try_data->register_number)) {
 	cx->frame->registers[try_data->register_number] = cx->throw_value;
       } else {
 	SWFDEC_ERROR ("cannot set Error to register %u: not enough registers",
 	    try_data->register_number);
       }
-    } else {
+    }
+    else
+    {
       // FIXME: this is duplicate of SetVariable
       SwfdecAsObject *object;
       const char *s, *rest;
@@ -2668,13 +2700,16 @@ swfdec_action_try_end_try (SwfdecAsFrame *frame, gpointer data)
       }
     }
 
+    swfdec_action_try_data_ref (try_data);
     swfdec_as_frame_push_block (frame, try_data->start,
 	try_data->start + try_data->catch_size, swfdec_action_try_end_catch,
-	try_data, NULL);
+	try_data, swfdec_action_try_data_unref);
 
     cx->throwing = FALSE;
     SWFDEC_AS_VALUE_SET_UNDEFINED (&cx->throw_value);
   }
+
+  swfdec_action_try_data_unref (try_data);
 }
 
 static void
@@ -2691,7 +2726,7 @@ swfdec_action_try (SwfdecAsContext *cx, guint action, const guint8 *data, guint
     return;
   }
 
-  try_data = g_malloc (sizeof (TryData));
+  try_data = g_malloc0 (sizeof (TryData));
 
   swfdec_bits_init_data (&bits, data, len);
 
@@ -2716,8 +2751,9 @@ swfdec_action_try (SwfdecAsContext *cx, guint action, const guint8 *data, guint
     SWFDEC_WARNING ("leftover bytes in Try action");
   }
 
+  swfdec_action_try_data_ref (try_data);
   swfdec_as_frame_push_block (cx->frame, data + len, data + len + try_size,
-      swfdec_action_try_end_try, try_data, NULL);
+      swfdec_action_try_end_try, try_data, swfdec_action_try_data_unref);
 }
 
 static void
commit 277fe3adc47d426ffede10e042a9d23c8b3f4955
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Oct 26 23:45:48 2007 +0300

    Implement Try and Throw ActionScript actions

diff --git a/libswfdec/swfdec_as_context.c b/libswfdec/swfdec_as_context.c
index 3d3215c..25ee0f1 100644
--- a/libswfdec/swfdec_as_context.c
+++ b/libswfdec/swfdec_as_context.c
@@ -809,6 +809,15 @@ start:
   check_block = TRUE;
 
   while (context->state < SWFDEC_AS_CONTEXT_ABORTED) {
+    while (context->throwing && frame->blocks->len > 0) {
+      frame->pc = frame->block_end;
+      swfdec_as_frame_check_block (frame);
+      pc = frame->pc;
+    }
+    if (context->throwing) {
+      swfdec_as_context_abort (context, "Unhandled exception");
+      goto error;
+    }
     if (check_block && (pc < frame->block_start || pc >= frame->block_end)) {
       SWFDEC_LOG ("code exited block");
       swfdec_as_frame_check_block (frame);
diff --git a/libswfdec/swfdec_as_context.h b/libswfdec/swfdec_as_context.h
index 8540cd8..0f062c8 100644
--- a/libswfdec/swfdec_as_context.h
+++ b/libswfdec/swfdec_as_context.h
@@ -63,6 +63,8 @@ struct _SwfdecAsContext {
   unsigned int		call_depth;   	/* current depth of call stack (equals length of frame list) */
   SwfdecAsFrame *	frame;		/* topmost stack frame */
   SwfdecAsFrame *	last_frame;   	/* last frame before calling context_run */
+  gboolean		throwing;	/* whether we are throwing an error */
+  SwfdecAsValue		throw_value;	/* the error object being thrown */
 
   /* stack */
   SwfdecAsValue	*	base;		/* stack base */
diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c
index af79c7b..3ab6fc0 100644
--- a/libswfdec/swfdec_as_interpret.c
+++ b/libswfdec/swfdec_as_interpret.c
@@ -2538,25 +2538,151 @@ static void
 swfdec_action_throw (SwfdecAsContext *cx, guint action, const guint8 *data,
     guint len)
 {
-  SwfdecAsValue *val;
-  SwfdecAsObject *object;
+  cx->throwing = TRUE;
+  cx->throw_value = *swfdec_as_stack_pop (cx);
+}
 
-  val = swfdec_as_stack_pop (cx);
-  if (SWFDEC_AS_VALUE_IS_OBJECT (val)) {
-    object = SWFDEC_AS_VALUE_GET_OBJECT (val);
-  } else {
-    object = NULL;
+typedef struct {
+  const guint8 *	start;
+  gboolean		catch;
+  gboolean		finally;
+  guint			catch_size;
+  guint			finally_size;
+
+  gboolean		use_register;
+  union {
+    guint		register_number;
+    char *		variable_name;
+  };
+} TryData;
+
+static void
+swfdec_action_try_free_data (TryData *try_data)
+{
+  g_return_if_fail (try_data != NULL);
+
+  if (!try_data->use_register)
+    g_free (try_data->variable_name);
+  g_free (try_data);
+}
+
+static void
+swfdec_action_try_end_finally (SwfdecAsFrame *frame, gpointer data)
+{
+  SwfdecAsValue *error = data;
+  SwfdecAsContext *cx;
+
+  g_return_if_fail (SWFDEC_IS_AS_FRAME (frame));
+  g_return_if_fail (SWFDEC_IS_AS_VALUE (error));
+
+  swfdec_as_frame_pop_block (frame);
+
+  cx = SWFDEC_AS_OBJECT (frame)->context;
+
+  if (!cx->throwing) {
+    cx->throwing = TRUE;
+    cx->throw_value = *error;
+  }
+}
+
+static void
+swfdec_action_try_end_catch (SwfdecAsFrame *frame, gpointer data)
+{
+  TryData *try_data = data;
+  SwfdecAsContext *cx;
+  SwfdecAsValue *error;
+
+  g_return_if_fail (SWFDEC_IS_AS_FRAME (frame));
+  g_return_if_fail (try_data != NULL);
+
+  cx = SWFDEC_AS_OBJECT (frame)->context;
+
+  swfdec_as_frame_pop_block (frame);
+
+  if (cx->throwing) {
+    error = g_malloc (sizeof (SwfdecAsValue));
+    *error = cx->throw_value;
+
+    swfdec_as_frame_push_block (frame, try_data->start + try_data->catch_size,
+	try_data->start + try_data->catch_size + try_data->finally_size,
+	swfdec_action_try_end_finally, error, g_free);
+
+    cx->throwing = FALSE;
+    SWFDEC_AS_VALUE_SET_UNDEFINED (&cx->throw_value);
   }
 
-  SWFDEC_FIXME ("Throw action not implemented");
+  swfdec_action_try_free_data (try_data);
+}
+
+static void
+swfdec_action_try_end_try (SwfdecAsFrame *frame, gpointer data)
+{
+  TryData *try_data = data;
+  SwfdecAsContext *cx;
+
+  g_return_if_fail (SWFDEC_IS_AS_FRAME (frame));
+  g_return_if_fail (try_data != NULL);
+
+  if (!try_data->catch) {
+    swfdec_action_try_end_catch (frame, try_data);
+    return;
+  }
+
+  cx = SWFDEC_AS_OBJECT (frame)->context;
+
+  swfdec_as_frame_pop_block (frame);
+
+  if (!cx->throwing) {
+    swfdec_action_try_free_data (try_data);
+  } else {
+    if (try_data->use_register) {
+      if (swfdec_action_has_register (cx, try_data->register_number)) {
+	cx->frame->registers[try_data->register_number] = cx->throw_value;
+      } else {
+	SWFDEC_ERROR ("cannot set Error to register %u: not enough registers",
+	    try_data->register_number);
+      }
+    } else {
+      // FIXME: this is duplicate of SetVariable
+      SwfdecAsObject *object;
+      const char *s, *rest;
+
+      s = swfdec_as_context_get_string (cx, try_data->variable_name);
+      if (swfdec_action_get_movie_by_path (cx, s, &object, &rest)) {
+	if (object && rest) {
+	  swfdec_as_object_set_variable (object,
+	      swfdec_as_context_get_string (cx, rest), &cx->throw_value);
+	} else {
+	  if (object) {
+	    rest = s;
+	  } else {
+	    rest = swfdec_as_context_get_string (cx, rest);
+	  }
+	  swfdec_as_frame_set_variable (frame, rest, &cx->throw_value);
+	}
+      }
+      else
+      {
+	SWFDEC_ERROR ("cannot set Error to variable %s",
+	    try_data->variable_name);
+      }
+    }
+
+    swfdec_as_frame_push_block (frame, try_data->start,
+	try_data->start + try_data->catch_size, swfdec_action_try_end_catch,
+	try_data, NULL);
+
+    cx->throwing = FALSE;
+    SWFDEC_AS_VALUE_SET_UNDEFINED (&cx->throw_value);
+  }
 }
 
 static void
 swfdec_action_try (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
 {
   SwfdecBits bits;
-  gboolean catch, finally, use_register;
-  guint try_size, catch_size, finally_size;
+  TryData *try_data;
+  guint try_size;
 
   if (len <= 8) {
     SWFDEC_ERROR ("With action requires a length of at least 8, but got %u",
@@ -2565,28 +2691,33 @@ swfdec_action_try (SwfdecAsContext *cx, guint action, const guint8 *data, guint
     return;
   }
 
+  try_data = g_malloc (sizeof (TryData));
+
   swfdec_bits_init_data (&bits, data, len);
 
   swfdec_bits_getbits (&bits, 5); // reserved
-  use_register = swfdec_bits_getbit (&bits);
-  finally = swfdec_bits_getbit (&bits);
-  catch = swfdec_bits_getbit (&bits);
+  try_data->use_register = swfdec_bits_getbit (&bits);
+  try_data->finally = swfdec_bits_getbit (&bits);
+  try_data->catch = swfdec_bits_getbit (&bits);
 
   try_size = swfdec_bits_get_u16 (&bits);
-  catch_size = swfdec_bits_get_u16 (&bits);
-  finally_size = swfdec_bits_get_u16 (&bits);
+  try_data->catch_size = swfdec_bits_get_u16 (&bits);
+  try_data->finally_size = swfdec_bits_get_u16 (&bits);
+  try_data->start = data + len + try_size;
 
-  if (use_register) {
-    swfdec_bits_get_u8 (&bits);
+  if (try_data->use_register) {
+    try_data->register_number = swfdec_bits_get_u8 (&bits);
   } else {
-    swfdec_bits_get_string_with_version (&bits, cx->version);
+    try_data->variable_name =
+      swfdec_bits_get_string_with_version (&bits, cx->version);
   }
 
   if (swfdec_bits_left (&bits)) {
     SWFDEC_WARNING ("leftover bytes in Try action");
   }
 
-  SWFDEC_FIXME ("Try action not implemented");
+  swfdec_as_frame_push_block (cx->frame, data + len, data + len + try_size,
+      swfdec_action_try_end_try, try_data, NULL);
 }
 
 static void
commit 48071596204d4a03f7d3f8da5d42130fb4d0d343
Author: Pekka Lampila <pekka.lampila at iki.fi>
Date:   Fri Oct 26 17:46:26 2007 +0300

    Add stubs for Try and Throw actions (just read the parameters, but do nothing)

diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c
index 1605a1a..af79c7b 100644
--- a/libswfdec/swfdec_as_interpret.c
+++ b/libswfdec/swfdec_as_interpret.c
@@ -1785,8 +1785,8 @@ swfdec_action_define_function (SwfdecAsContext *cx, guint action,
   char *function_name;
   const char *name = NULL;
   guint i, n_args, size, n_registers;
-  SwfdecBuffer *buffer;
   SwfdecBits bits;
+  SwfdecBuffer *buffer;
   SwfdecAsFunction *fun;
   SwfdecAsFrame *frame;
   SwfdecScript *script;
@@ -2535,6 +2535,61 @@ swfdec_action_mb_ascii_to_char_5 (SwfdecAsContext *cx, guint action, const guint
 }
 
 static void
+swfdec_action_throw (SwfdecAsContext *cx, guint action, const guint8 *data,
+    guint len)
+{
+  SwfdecAsValue *val;
+  SwfdecAsObject *object;
+
+  val = swfdec_as_stack_pop (cx);
+  if (SWFDEC_AS_VALUE_IS_OBJECT (val)) {
+    object = SWFDEC_AS_VALUE_GET_OBJECT (val);
+  } else {
+    object = NULL;
+  }
+
+  SWFDEC_FIXME ("Throw action not implemented");
+}
+
+static void
+swfdec_action_try (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+  SwfdecBits bits;
+  gboolean catch, finally, use_register;
+  guint try_size, catch_size, finally_size;
+
+  if (len <= 8) {
+    SWFDEC_ERROR ("With action requires a length of at least 8, but got %u",
+	len);
+    swfdec_as_stack_pop (cx);
+    return;
+  }
+
+  swfdec_bits_init_data (&bits, data, len);
+
+  swfdec_bits_getbits (&bits, 5); // reserved
+  use_register = swfdec_bits_getbit (&bits);
+  finally = swfdec_bits_getbit (&bits);
+  catch = swfdec_bits_getbit (&bits);
+
+  try_size = swfdec_bits_get_u16 (&bits);
+  catch_size = swfdec_bits_get_u16 (&bits);
+  finally_size = swfdec_bits_get_u16 (&bits);
+
+  if (use_register) {
+    swfdec_bits_get_u8 (&bits);
+  } else {
+    swfdec_bits_get_string_with_version (&bits, cx->version);
+  }
+
+  if (swfdec_bits_left (&bits)) {
+    SWFDEC_WARNING ("leftover bytes in Try action");
+  }
+
+  SWFDEC_FIXME ("Try action not implemented");
+}
+
+static void
 swfdec_action_pop_with (SwfdecAsFrame *frame, gpointer with_object)
 {
   g_assert (frame->scope_chain->data == with_object);
@@ -2959,7 +3014,7 @@ const SwfdecActionSpec swfdec_as_actions[256] = {
   [SWFDEC_AS_ACTION_END_DRAG] = { "EndDrag", NULL, 0, 0, { NULL, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag } },
   [SWFDEC_AS_ACTION_STRING_LESS] = { "StringLess", NULL, 2, 1, { NULL, swfdec_action_string_compare, swfdec_action_string_compare, swfdec_action_string_compare, swfdec_action_string_compare } },
   /* version 7 */
-  [SWFDEC_AS_ACTION_THROW] = { "Throw", NULL },
+  [SWFDEC_AS_ACTION_THROW] = { "Throw", NULL, 1, 0, { NULL, NULL, NULL, NULL, swfdec_action_throw } },
   [SWFDEC_AS_ACTION_CAST] = { "Cast", NULL, 2, 1, { NULL, NULL, NULL, NULL, swfdec_action_cast } },
   [SWFDEC_AS_ACTION_IMPLEMENTS] = { "Implements", NULL, -1, 0, { NULL, NULL, NULL, NULL, swfdec_action_implements } },
   /* version 4 */
@@ -3032,7 +3087,7 @@ const SwfdecActionSpec swfdec_as_actions[256] = {
 #endif
   /* version 7 */
   [SWFDEC_AS_ACTION_DEFINE_FUNCTION2] = { "DefineFunction2", swfdec_action_print_define_function, 0, -1, { NULL, NULL, NULL, swfdec_action_define_function, swfdec_action_define_function } },
-  [SWFDEC_AS_ACTION_TRY] = { "Try", NULL },
+  [SWFDEC_AS_ACTION_TRY] = { "Try", NULL, 0, 0, { NULL, NULL, NULL, NULL, swfdec_action_try } },
   /* version 5 */
   [SWFDEC_AS_ACTION_WITH] = { "With", swfdec_action_print_with, 1, 0, { NULL, NULL, swfdec_action_with, swfdec_action_with, swfdec_action_with } },
   /* version 4 */


More information about the Swfdec mailing list