Pekka Lampila
2007-Oct-26 21:27 UTC
[Swfdec] 3 commits - libswfdec/swfdec_as_context.c libswfdec/swfdec_as_context.h libswfdec/swfdec_as_interpret.c
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 */
Apparently Analagous Threads
- 8 commits - doc/swfdec-sections.txt libswfdec/swfdec_as_context.c libswfdec/swfdec_as_context.h libswfdec/swfdec_as_interpret.c test/trace
- 4 commits - libswfdec-gtk/swfdec_gtk_loader.c libswfdec/swfdec_as_context.c libswfdec/swfdec_as_frame.c libswfdec/swfdec_as_frame_internal.h libswfdec/swfdec_as_interpret.c libswfdec/swfdec_loader.c libswfdec/swfdec_loader.h libswfdec/swfdec_load_object.c
- 6 commits - libswfdec/Makefile.am libswfdec/swfdec_as_interpret.c libswfdec/swfdec_color_as.c libswfdec/swfdec_graphic_movie.c libswfdec/swfdec_image_decoder.c libswfdec/swfdec_morph_movie.c libswfdec/swfdec_movie_as_drawing.c
- 20 commits - libswfdec/Makefile.am libswfdec/swfdec_as_interpret.c libswfdec/swfdec_html_parser.c libswfdec/swfdec_initialize.as libswfdec/swfdec_initialize.h libswfdec/swfdec_text_field.c libswfdec/swfdec_text_field.h
- Seeking advice on lattice package in R2.4.0 concerning stripplot