[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