Benjamin Otte
2007-Feb-06 10:29 UTC
[Swfdec] 109 commits - configure.ac libswfdec/js libswfdec/Makefile.am libswfdec/swfdec_bits.c libswfdec/swfdec_bits.h libswfdec/swfdec_buffer.c libswfdec/swfdec_button_movie.c libswfdec/swfdec_codec_screen.c libswfdec/swfdec_color.c libswfdec/swfdec_color.h libswfdec/swfdec_compiler.c libswfdec/swfdec_compiler.h libswfdec/swfdec_debugger.c libswfdec/swfdec_debugger.h libswfdec/swfdec_event.c libswfdec/swfdec_event.h libswfdec/swfdec_image.c libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c libswfdec/swfdec_js_global.c libswfdec/swfdec_js.h libswfdec/swfdec_js_movie.c libswfdec/swfdec_js_sound.c libswfdec/swfdec_movie.c libswfdec/swfdec_movie.h libswfdec/swfdec_player.c libswfdec/swfdec_player_internal.h libswfdec/swfdec_root_movie.c libswfdec/swfdec_scriptable.c libswfdec/swfdec_script.c libswfdec/swfdec_script.h libswfdec/swfdec_sound.c libswfdec/swfdec_sound.h libswfdec/swfdec_sprite.c libswfdec/swfdec_sprite_movie.c libswfdec/swfdec_swf_decoder.c libswfdec/swfdec_tag.c libswfdec/swfdec_text.c libswfdec/swfdec_types.h player/swfdebug.c player/swfdec_debug_scripts.c player/swfdec_debug_stack.c player/swfdec_player_manager.c test/dump.c test/Makefile.am test/swfdec-extract.c test/swfdec_out.c test/swfdec_out.h test/swfedit.c test/swfedit_file.c test/swfedit_file.h test/swfedit_tag.c test/swfedit_tag.h test/swfedit_token.c test/swfedit_token.h test/trace
configure.ac | 2 libswfdec/Makefile.am | 4 libswfdec/js/jsfun.c | 11 libswfdec/js/jsfun.h | 1 libswfdec/js/jsgc.c | 29 libswfdec/js/jsinterp.c | 14 libswfdec/js/jsinterp.h | 4 libswfdec/js/jsnum.c | 10 libswfdec/js/jsobj.c | 2 libswfdec/swfdec_bits.c | 61 libswfdec/swfdec_bits.h | 13 libswfdec/swfdec_buffer.c | 7 libswfdec/swfdec_button_movie.c | 3 libswfdec/swfdec_codec_screen.c | 2 libswfdec/swfdec_color.c | 4 libswfdec/swfdec_color.h | 2 libswfdec/swfdec_compiler.c | 1521 ----------------------- libswfdec/swfdec_compiler.h | 22 libswfdec/swfdec_debugger.c | 116 + libswfdec/swfdec_debugger.h | 16 libswfdec/swfdec_event.c | 14 libswfdec/swfdec_event.h | 2 libswfdec/swfdec_image.c | 165 +- libswfdec/swfdec_js.c | 154 +- libswfdec/swfdec_js.h | 4 libswfdec/swfdec_js_color.c | 39 libswfdec/swfdec_js_global.c | 3 libswfdec/swfdec_js_movie.c | 29 libswfdec/swfdec_js_sound.c | 7 libswfdec/swfdec_movie.c | 26 libswfdec/swfdec_movie.h | 1 libswfdec/swfdec_player.c | 10 libswfdec/swfdec_player_internal.h | 2 libswfdec/swfdec_root_movie.c | 8 libswfdec/swfdec_script.c | 2374 +++++++++++++++++++++++++++++++++++++ libswfdec/swfdec_script.h | 71 + libswfdec/swfdec_scriptable.c | 2 libswfdec/swfdec_sound.c | 13 libswfdec/swfdec_sound.h | 2 libswfdec/swfdec_sprite.c | 4 libswfdec/swfdec_sprite_movie.c | 4 libswfdec/swfdec_swf_decoder.c | 48 libswfdec/swfdec_tag.c | 29 libswfdec/swfdec_text.c | 3 libswfdec/swfdec_types.h | 1 player/swfdebug.c | 4 player/swfdec_debug_scripts.c | 2 player/swfdec_debug_stack.c | 33 player/swfdec_player_manager.c | 8 test/Makefile.am | 21 test/dump.c | 34 test/swfdec-extract.c | 2 test/swfdec_out.c | 258 ++++ test/swfdec_out.h | 78 + test/swfedit.c | 131 ++ test/swfedit_file.c | 287 ++++ test/swfedit_file.h | 59 test/swfedit_tag.c | 253 +++ test/swfedit_tag.h | 66 + test/swfedit_token.c | 573 ++++++++ test/swfedit_token.h | 90 + test/trace/.gitignore | 1 test/trace/Makefile.am | 14 test/trace/color-new.swf |binary test/trace/color-new.swf.trace | 10 test/trace/function1.swf |binary test/trace/function1.swf.trace | 50 test/trace/function2.swf |binary test/trace/function2.swf.trace | 2 test/trace/number.swf |binary test/trace/number.swf.trace | 9 test/trace/object-math-5.swf |binary test/trace/object-math-5.swf.trace | 17 test/trace/object-math-6.swf |binary test/trace/object-math-6.swf.trace | 17 test/trace/object-math-7.swf |binary test/trace/object-math-7.swf.trace | 17 77 files changed, 4969 insertions(+), 1926 deletions(-) New commits: diff-tree ee3339e4cb9af7e52a6ecb381206f1ea5adb07c0 (from 24e1974f101eb00c1d7017dc3b90ba7009c7808f) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 14:59:28 2007 +0100 s/unsigned int/SwfdecColor/ for colors diff --git a/libswfdec/swfdec_color.c b/libswfdec/swfdec_color.c index ee3a63f..c4fa52e 100644 --- a/libswfdec/swfdec_color.c +++ b/libswfdec/swfdec_color.c @@ -82,8 +82,8 @@ swfdec_color_apply_transform_premultipli return SWFDEC_COLOR_COMBINE (r, g, b, a); } -unsigned int -swfdec_color_apply_transform (unsigned int in, const SwfdecColorTransform * trans) +SwfdecColor +swfdec_color_apply_transform (SwfdecColor in, const SwfdecColorTransform * trans) { int r, g, b, a; diff --git a/libswfdec/swfdec_color.h b/libswfdec/swfdec_color.h index 54ce268..a7a7723 100644 --- a/libswfdec/swfdec_color.h +++ b/libswfdec/swfdec_color.h @@ -75,7 +75,7 @@ void swfdec_color_transform_init_color ( gboolean swfdec_color_transform_is_identity (const SwfdecColorTransform * trans); void swfdec_color_transform_chain (SwfdecColorTransform *dest, const SwfdecColorTransform *last, const SwfdecColorTransform *first); -unsigned int swfdec_color_apply_transform (unsigned int in, +SwfdecColor swfdec_color_apply_transform (SwfdecColor in, const SwfdecColorTransform * trans); SwfdecColor swfdec_color_apply_transform_premultiplied (SwfdecColor in, const SwfdecColorTransform * trans); diff --git a/libswfdec/swfdec_text.c b/libswfdec/swfdec_text.c index 4d3ad03..d7ca655 100644 --- a/libswfdec/swfdec_text.c +++ b/libswfdec/swfdec_text.c @@ -58,7 +58,8 @@ static void swfdec_text_render (SwfdecGraphic *graphic, cairo_t *cr, const SwfdecColorTransform *trans, const SwfdecRect *inval, gboolean fill) { - unsigned int i, color; + unsigned int i; + SwfdecColor color; SwfdecText *text = SWFDEC_TEXT (graphic); SwfdecColorTransform force_color; SwfdecRect rect, inval_moved; diff-tree 24e1974f101eb00c1d7017dc3b90ba7009c7808f (from 7224f1a88cc0de6a42f05f44a5c96a366a8b775b) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 14:53:54 2007 +0100 fix code assuming sound->n_samples is in decoded format instead of 44100kHz diff --git a/libswfdec/swfdec_sound.c b/libswfdec/swfdec_sound.c index 1620f5d..7f302c1 100644 --- a/libswfdec/swfdec_sound.c +++ b/libswfdec/swfdec_sound.c @@ -235,17 +235,22 @@ swfdec_sound_get_decoded (SwfdecSound *s tmp = tmp2; } /* sound buffer may be bigger due to mp3 not having sample boundaries */ - if (tmp->length > sound->n_samples * sample_bytes) { - SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, 0, sound->n_samples * sample_bytes); + if (tmp->length * SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format) + > sound->n_samples * sample_bytes) { + SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, 0, + sound->n_samples * sample_bytes / SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format)); swfdec_buffer_unref (tmp); tmp = tmp2; } - if (tmp->length < sound->n_samples * sample_bytes) { + if (tmp->length * SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format) + < sound->n_samples * sample_bytes) { /* we handle this case in swfdec_sound_render */ /* FIXME: this message is important when writing new codecs, so I made it a warning. * It's probably not worth more than INFO for the usual case though */ SWFDEC_WARNING ("%u samples in %u bytes should be available, but only %u bytes are", - sound->n_samples, sound->n_samples * sample_bytes, tmp->length); + sound->n_samples / SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format), + sound->n_samples * sample_bytes / SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format), + tmp->length); } /* only assign here, the decoding code checks this variable */ sound->decoded = tmp; diff --git a/libswfdec/swfdec_sound.h b/libswfdec/swfdec_sound.h index 7bf26ec..ce837db 100644 --- a/libswfdec/swfdec_sound.h +++ b/libswfdec/swfdec_sound.h @@ -66,7 +66,7 @@ struct _SwfdecSound SwfdecAudioFormat format; /* format in use */ gboolean width; /* TRUE for 16bit, FALSE for 8bit */ SwfdecAudioOut original_format; /* channel/rate information */ - unsigned int n_samples; /* total number of samples */ + unsigned int n_samples; /* total number of samples when decoded to 44100kHz */ unsigned int skip; /* samples to skip at start */ SwfdecBuffer * encoded; /* encoded data */ diff-tree 7224f1a88cc0de6a42f05f44a5c96a366a8b775b (from ffeec3ded24753fe7b291e6054146d641425233c) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 14:39:21 2007 +0100 add the temporary tmp file diff --git a/test/trace/.gitignore b/test/trace/.gitignore index 25a10a8..8840a6f 100644 --- a/test/trace/.gitignore +++ b/test/trace/.gitignore @@ -8,4 +8,5 @@ Makefile Makefile.in *.o +tmp trace diff-tree ffeec3ded24753fe7b291e6054146d641425233c (from 375b6d4dc5d4335c3fcafa0ce96076287ae2b9ac) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 12:43:55 2007 +0100 delete the old compiler source files diff --git a/libswfdec/swfdec_compiler.c b/libswfdec/swfdec_compiler.c deleted file mode 100644 index 9947f19..0000000 --- a/libswfdec/swfdec_compiler.c +++ /dev/null @@ -1,1504 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> -#include <string.h> - -#include <js/jsapi.h> -#include <js/jsarena.h> -#include <js/jsatom.h> -#include <js/jsemit.h> -#include <js/jsscript.h> -#include <js/jsopcode.h> - -#include "swfdec_bits.h" -#include "swfdec_compiler.h" -#include "swfdec_debug.h" -#include "swfdec_debugger.h" -#include "swfdec_player_internal.h" -#include "swfdec_sprite.h" - -/*** NOTE TO HACKERS *** - - This file is supposed to contain a compiler that compiles ActionScript code - as found in an swf file to Javascript bytecode ready to be interpreted by - the Spidermonkey engine. - The problem here is that I have not much of a clue on how to do such a thing - right, the SpiderMonkey docs are very nice for users but unfortunately not for - people mocking with bytecode. I guess the contents of this file reflects that. - So if you can do better, this file has just one public function: - swfdec_compile (). Feel free to reimplement it in a better way. - - *** END NOTE TO HACKERS ***/ - -/*** COMPILE STATE ***/ - -typedef struct { - guint bytecode; /* offset into bytecode where jump address goes */ - gboolean extended; /* if this is an extended jump */ - gboolean use_bytes; /* if TRUE, the offset is in bytes, otherwise it's in actions */ - guint offset; /* action to jump to */ -} Jump; - -typedef struct { - guint original; /* amount of bytes we've advanced in the input */ - guint compiled; /* amount of bytes we've advancecd in the bytecode */ -} Offset; - -typedef struct { - JSContext * cx; /* JSContext from player */ - JSAtomList atoms; /* accumulated atoms */ - - SwfdecBits * bits; /* where to read the code from */ - int version; /* Flash version we're compiling for */ - GByteArray * bytecode; /* generated bytecode so far */ - char * error; /* error encountered while compiling */ - GArray * offsets; /* offsets of actions */ - GArray * jumps; /* accumulated jumps */ - GArray * trynotes; /* try/catch blocks */ - GPtrArray * pool; /* ConstantPool data */ - GArray * commands; /* debug informations */ - guint command_last; /* offset to last command */ -} CompileState; - -/*** DEBUGGING STUFF ***/ - -/* NB: this must be called _before_ adding bytecode */ -static void -compile_state_debug_add (CompileState *state, const char *format, ...) G_GNUC_PRINTF (2, 3); -static void -compile_state_debug_add (CompileState *state, const char *format, ...) -{ - va_list args; - SwfdecDebuggerCommand command = { NULL, }; - - command.code = NULL + state->bytecode->len; - command.breakpoint = 0; - va_start (args, format); - command.description = g_strdup_vprintf (format, args); - SWFDEC_DEBUG ("%s", command.description); - va_end (args); - state->command_last = G_MAXUINT; - g_array_append_val (state->commands, command); -} - -static void -compile_state_debug_add_default (CompileState *state, guint action, const char *name) -{ - SwfdecDebuggerCommand command = { NULL, }; - - if (state->command_last == G_MAXUINT) - return; - if (action & 0x80) { - SWFDEC_WARNING ("FIXME: action %s does not provide debugger statements", name); - } - command.code = GUINT_TO_POINTER (state->command_last); - command.description = g_strdup (name); - state->command_last = G_MAXUINT; - g_array_append_val (state->commands, command); - SWFDEC_DEBUG ("%s", command.description); -} - -static void -compile_state_debug_finish (CompileState *state, SwfdecPlayer *player, JSScript *script, const char *name) -{ - SwfdecDebuggerCommand *command; - guint i; - - if (SWFDEC_IS_DEBUGGER (player)) { - for (i = 0; i < state->commands->len; i++) { - command = &g_array_index (state->commands, SwfdecDebuggerCommand, i); - command->code = script->code + GPOINTER_TO_UINT (command->code); - } - swfdec_debugger_add_script (SWFDEC_DEBUGGER (player), script, name, - (SwfdecDebuggerCommand *) state->commands->data, state->commands->len); - g_array_free (state->commands, FALSE); - } else { - g_array_free (state->commands, TRUE); - } -} - -/*** GENERAL FUNCTIONS ***/ - -static void -compile_state_error (CompileState *state, char *format, ...) G_GNUC_PRINTF (2, 3); -static void -compile_state_error (CompileState *state, char *format, ...) -{ - va_list args; - - g_assert (state->error == NULL); - - va_start (args, format); - state->error = g_strdup_vprintf (format, args); - va_end (args); -} - -/*** ACTION COMPILATION FUNCTIONS ***/ - -static void -compile_state_push_offset (CompileState *state, guint command_len) -{ - Offset offset = { command_len, state->bytecode->len }; - if (state->offsets->len > 0) - offset.original += g_array_index (state->offsets, Offset, state->offsets->len - 1).original; - g_array_append_val (state->offsets, offset); -} - -static jsatomid -atomize_string (CompileState *state, const char *name) -{ - JSAtom *atom; - JSAtomListElement *ale; - - atom = js_Atomize (state->cx, name, strlen (name), 0); - ale = js_IndexAtom (state->cx, atom, &state->atoms); - if (ale == NULL) { - compile_state_error (state, "Failed to add name %s", name); - return 0; - } - return ALE_INDEX (ale); -} - -static jsatomid -atomize_double (CompileState *state, jsdouble d) -{ - JSAtom *atom; - JSAtomListElement *ale; - - atom = js_AtomizeDouble (state->cx, d, 0); - ale = js_IndexAtom (state->cx, atom, &state->atoms); - if (ale == NULL) { - compile_state_error (state, "Failed to add double %g", d); - return 0; - } - return ALE_INDEX (ale); -} - -static jsatomid -atomize_int32 (CompileState *state, int i) -{ - JSAtom *atom; - JSAtomListElement *ale; - - g_assert (i >= G_MININT32 && i <= G_MAXINT32); - atom = js_AtomizeInt (state->cx, i, 0); - ale = js_IndexAtom (state->cx, atom, &state->atoms); - if (ale == NULL) { - compile_state_error (state, "Failed to add int %d", i); - return 0; - } - return ALE_INDEX (ale); -} - -#define ONELINER(state, opcode) G_STMT_START { \ - guint8 command = opcode; \ - compile_state_add_code (state, &command, 1); \ -} G_STMT_END -#define THREELINER(state, opcode, id1, id2) G_STMT_START { \ - guint8 command[3] = { opcode, id1, id2 }; \ - compile_state_add_code (state, command, 3); \ -} G_STMT_END -#define THREELINER_INT(state, opcode, _int) THREELINER (state, opcode, (_int) >> 8, (_int)) -#define THREELINER_ATOM(state, opcode, str) G_STMT_START { \ - jsatomid id; \ - id = atomize_string (state, str); \ - THREELINER_INT (state, opcode, id); \ -} G_STMT_END - -#define PUSH_OBJ(state) ONELINER (state, JSOP_PUSHOBJ) -#define POP(state) ONELINER (state, JSOP_POP) -#define GE(state) ONELINER (state, JSOP_GE) -#define THIS(state) ONELINER (state, JSOP_THIS) -#define SWAP(state) ONELINER (state, JSOP_SWAP) -#define DUP(state) ONELINER (state, JSOP_DUP) -#define FLASHCALL(state) ONELINER (state, JSOP_FLASHCALL) -#define FLASHSWAP(state, n) THREELINER_INT (state, JSOP_FLASHSWAP, n) - -#define DO_JUMP(state, opcode, offset) G_STMT_START {\ - guint8 command[3] = { opcode, 0, 0 }; \ - compile_state_add_bytes_jump (state, offset, FALSE); \ - compile_state_add_code (state, command, 3); \ -} G_STMT_END -#define IFEQ(state, offset) DO_JUMP (state, JSOP_IFEQ, offset) -#define IFNE(state, offset) DO_JUMP (state, JSOP_IFNE, offset) - -static void -compile_state_add_code (CompileState *state, const guint8 *code, guint len) -{ - if (state->error) - return; - g_byte_array_append (state->bytecode, code, len); -} - -static void -bind_name (CompileState *state, const char *name) -{ - THREELINER_ATOM (state, JSOP_BINDNAME, name); -} - -#define TARGET_NAME "__swfdec_target" -static void -compile_state_set_target (CompileState *state) -{ - guint8 command[3] = { JSOP_BINDNAME, 0, 0 }; - compile_state_add_code (state, command, 3); - SWAP (state); - command[0] = JSOP_SETNAME; - compile_state_add_code (state, command, 3); - POP (state); -} -static void -compile_state_add_target (CompileState *state) -{ - guint8 command[3] = { JSOP_DEFVAR, 0, 0 }; - /* add the TARGET variable */ - if (atomize_string (state, TARGET_NAME) != 0) { - g_assert_not_reached (); - } - compile_state_add_code (state, command, 3); - THIS (state); - compile_state_set_target (state); -} - -static void -compile_state_init (JSContext *cx, SwfdecBits *bits, int version, CompileState *state) -{ - state->cx = cx; - state->bits = bits; - state->version = version; - ATOM_LIST_INIT (&state->atoms); - state->bytecode = g_byte_array_new (); - state->error = NULL; - state->offsets = g_array_new (FALSE, FALSE, sizeof (Offset)); - state->jumps = g_array_new (FALSE, FALSE, sizeof (Jump)); - state->trynotes = g_array_new (TRUE, FALSE, sizeof (JSTryNote)); - state->pool = g_ptr_array_new (); - state->commands = g_array_new (TRUE, FALSE, sizeof (SwfdecDebuggerCommand)); - state->command_last = G_MAXUINT; - - compile_state_add_target (state); - compile_state_push_offset (state, 0); -} - -static void -compile_state_resolve_jumps (CompileState *state) -{ - guint i, j; - int offset; - Jump *jump; - guint8 *bytecode; - - for (i = 0; i < state->jumps->len; i++) { - jump = &g_array_index (state->jumps, Jump, i); - bytecode = state->bytecode->data + jump->bytecode + 1; - if (jump->use_bytes) { - for (j = 0; j < state->offsets->len; j++) { - if (g_array_index (state->offsets, Offset, j).original == jump->offset) { - offset = g_array_index (state->offsets, Offset, j).compiled; - offset -= jump->bytecode; - goto finished; - } - } - compile_state_error (state, "Jumped into action"); - return; - } else { - offset = g_array_index (state->offsets, Offset, - MIN (state->offsets->len - 1, jump->offset)).compiled; - offset -= jump->bytecode; - } -finished: - if (jump->extended) { - gint32 *data = (gint32 *) bytecode; - *data = GINT32_TO_BE (offset); - } else { - gint16 *data = (gint16 *) bytecode; - if (offset > G_MAXINT32 || offset < G_MININT32) { - compile_state_error (state, "jump from %u to %u is too big", - jump->bytecode, MIN (state->offsets->len - 1, jump->offset)); - return; - } - *data = GINT16_TO_BE (offset); - } - } -} - -#define OFFSET_MAIN 3 -static JSScript * -compile_state_finish (CompileState *state, SwfdecPlayer *player, const char *name) -{ - JSContext *cx = state->cx; - JSScript *script = NULL; - - if (state->error == NULL) - compile_state_resolve_jumps (state); - - if (state->error != NULL) { - JSAtomMap clear; - js_InitAtomMap (cx, &clear, &state->atoms); - js_FreeAtomMap (cx, &clear); - SWFDEC_ERROR ("%s", state->error); - g_free (state->error); - goto cleanup; - } - - script = js_NewScript (cx, state->bytecode->len, 1, state->trynotes->len + 1); - memcpy (script->code, state->bytecode->data, state->bytecode->len); - memcpy (script->trynotes, state->trynotes->data, (state->trynotes->len + 1) * sizeof (JSTryNote)); - js_InitAtomMap (cx, &script->atomMap, &state->atoms); - /* FIXME: figure out a correct value here */ - script->depth = 100; - script->main = script->code + OFFSET_MAIN; - SN_MAKE_TERMINATOR (SCRIPT_NOTES (script)); - compile_state_debug_finish (state, player, script, name); - -cleanup: - g_ptr_array_free (state->pool, TRUE); - g_array_free (state->offsets, TRUE); - g_array_free (state->jumps, TRUE); - g_array_free (state->trynotes, TRUE); - g_byte_array_free (state->bytecode, TRUE); - return script; -} - -static void -add_try_catch_block (CompileState *state, guint n_bytes, guint pc_offset) -{ - ptrdiff_t last = 0; - ptrdiff_t cur_offset; - JSTryNote tn; - - g_assert (state->bytecode->len >= OFFSET_MAIN); - cur_offset = state->bytecode->len - OFFSET_MAIN; - if (state->trynotes->len > 0) { - JSTryNote *tmp = &g_array_index (state->trynotes, JSTryNote, state->trynotes->len - 1); - last = tmp->start + tmp->length; - /* FIXME: allow nesting of try/catch blocks */ - g_assert (last <= cur_offset); - } - if (last < cur_offset) { - /* add "no catching here" note */ - tn.start = last; - tn.length = cur_offset - last; - tn.catchStart = 0; - g_array_append_val (state->trynotes, tn); - } - tn.start = cur_offset; - tn.length = n_bytes; - tn.catchStart = state->bytecode->len + pc_offset - OFFSET_MAIN; - SWFDEC_LOG ("adding try/catch at %u (len %u) to offset %u", - tn.start, tn.length, tn.catchStart); - g_array_append_val (state->trynotes, tn); -} - -/* NB: n_bytes is relative to the start of this action */ -static void -compile_state_add_bytes_jump (CompileState *state, int n_bytes, gboolean extended) -{ - Jump jump = { state->bytecode->len, extended, TRUE, - n_bytes + g_array_index (state->offsets, Offset, state->offsets->len - 1).original }; - - SWFDEC_LOG ("adding jump to byte %u", jump.offset); - if (n_bytes < 0 && - (guint) -n_bytes > g_array_index (state->offsets, Offset, state->offsets->len - 1).original) { - compile_state_error (state, "attempting to jump %d bytess backwards at byte %u", - -n_bytes, g_array_index (state->offsets, Offset, state->offsets->len - 1).original); - return; - } - g_array_append_val (state->jumps, jump); -} - -/* must be called before adding the jump command to the bytecode */ -static void -compile_state_add_action_jump (CompileState *state, int n_actions, gboolean extended) -{ - Jump jump = { state->bytecode->len, extended, FALSE, state->offsets->len + n_actions }; - - if (n_actions < 0 && state->offsets->len < (guint) -n_actions) { - compile_state_error (state, "attempting to jump %d actions backwards in %u. action", - -n_actions, state->offsets->len); - return; - } - g_array_append_val (state->jumps, jump); -} - -static void -push_target (CompileState *state) -{ - THREELINER (state, JSOP_NAME, 0, 0); -} - -static void -push_prop (CompileState *state, const char *name) -{ - THREELINER_ATOM (state, JSOP_GETPROP, name); -} - -static void -name (CompileState *state, const char *name) -{ - THREELINER_ATOM (state, JSOP_NAME, name); -} - -#if 0 -static void -push_prop_without_target (CompileState *state, const char *name) -{ - jsatomid id; - guint8 command[3]; - - id = atomize_string (state, name); - command[0] = JSOP_BINDNAME; - command[1] = id >> 8; - command[2] = id; - compile_state_add_code (state, command, 3); - command[0] = JSOP_GETPROP; - compile_state_add_code (state, command, 3); -} -#endif - -static void -push_uint16 (CompileState *state, unsigned int i) -{ - g_assert (i <= G_MAXUINT16); - SWFDEC_LOG ("pushing %u", i); - THREELINER_INT (state, JSOP_UINT16, i); -} - -static void -call (CompileState *state, guint n_arguments) -{ - THREELINER_INT (state, JSOP_CALL, n_arguments); -} - -static void -call_void_function (CompileState *state, const char *name) -{ - push_prop (state, name); - PUSH_OBJ (state); - call (state, 0); - POP (state); -} - -/* 13 bytes */ -#define DEBUG_TRACE(state) G_STMT_START { \ - ONELINER (state, JSOP_DUP); \ - compile_trace (state, 0, 0); \ -}G_STMT_END - -static void -compile_trace (CompileState *state, guint action, guint len) -{ - push_uint16 (state, 1); - bind_name (state, "trace"); - push_prop (state, "trace"); - PUSH_OBJ (state); - FLASHCALL (state); - POP (state); -} - -static void -compile_get_variable (CompileState *state, guint action, guint len) -{ - push_uint16 (state, 1); - push_target (state); - push_prop (state, "eval"); - push_target (state); - FLASHCALL (state); -} - -static void -compile_set_variable (CompileState *state, guint action, guint len) -{ - /* FIXME: handle paths */ - push_target (state); - FLASHSWAP (state, 3); - SWAP (state); - ONELINER (state, JSOP_SETELEM); - POP (state); -} - -static void -push_string (CompileState *state, const char *s) -{ - SWFDEC_LOG ("pushing string: %s", s); - THREELINER_ATOM (state, JSOP_STRING, s); -} - -static void -push_double (CompileState *state, double d) -{ - jsatomid id = atomize_double (state, d); - - SWFDEC_LOG ("pushing double: %g", d); - THREELINER_INT (state, JSOP_NUMBER, id); -} - -static void -push_int32 (CompileState *state, gint32 i) -{ - jsatomid id = atomize_int32 (state, i); - SWFDEC_LOG ("pushing int: %d", i); - THREELINER_INT (state, JSOP_NUMBER, id); -} - -static void -compile_push (CompileState *state, guint action, guint len) -{ - SwfdecBits *bits = state->bits; - guint type; - unsigned char *end = bits->ptr + len; - double d; - int i; - const char *s; - - while (bits->ptr < end) { - type = swfdec_bits_get_u8 (bits); - SWFDEC_LOG ("push type %u", type); - switch (type) { - case 0: /* string */ - s = swfdec_bits_skip_string (state->bits); - if (s == NULL) { - compile_state_error (state, "Push: Could not get string"); - return; - } - compile_state_debug_add (state, "Push \"%s\"", s); - push_string (state, s); - break; - case 1: /* float */ - d = swfdec_bits_get_float (state->bits); - compile_state_debug_add (state, "Push %g", d); - push_double (state, d); - break; - case 2: /* null */ - compile_state_debug_add (state, "Push null"); - ONELINER (state, JSOP_NULL); - break; - case 3: /* undefined */ - compile_state_debug_add (state, "Push undefined"); - ONELINER (state, JSOP_NULL); - ONELINER (state, JSOP_VOID); - break; - case 5: /* boolean */ - type = swfdec_bits_get_u8 (bits); - if (type) { - compile_state_debug_add (state, "Push TRUE"); - ONELINER (state, JSOP_TRUE); - } else { - compile_state_debug_add (state, "Push FALSE"); - ONELINER (state, JSOP_FALSE); - } - break; - case 6: /* double */ - d = swfdec_bits_get_double (state->bits); - compile_state_debug_add (state, "Push %g", d); - push_double (state, d); - break; - case 7: /* 32bit int */ - /* FIXME: spec says U32, do they mean this? */ - i = swfdec_bits_get_u32 (state->bits); - compile_state_debug_add (state, "Push %d", i); - push_int32 (state, i); - break; - case 8: /* 8bit ConstantPool address */ - type = swfdec_bits_get_u8 (bits); - if (type >= state->pool->len) { - compile_state_error (state, "Constant pool index %u out of range %u", - type, state->pool->len); - return; - } - s = (const char *) g_ptr_array_index (state->pool, type); - compile_state_debug_add (state, "Push \"%s\"", s); - push_string (state, s); - break; - case 9: /* 16bit ConstantPool address */ - type = swfdec_bits_get_u16 (bits); - if (type >= state->pool->len) { - compile_state_error (state, "Constant pool index %u out of range %u", - type, state->pool->len); - return; - } - s = (const char *) g_ptr_array_index (state->pool, type); - compile_state_debug_add (state, "Push \"%s\"", s); - push_string (state, s); - break; - case 4: /* register */ - default: - compile_state_error (state, "Push: type %u not implemented", type); - swfdec_bits_getbits (bits, 8 * (end - bits->ptr)); - } - } -} - -static void -compile_goto_label (CompileState *state, guint action, guint len) -{ - const char *s; - - s = swfdec_bits_skip_string (state->bits); - compile_state_debug_add (state, "GotoLabel \"%s\"s", s); - push_target (state); - push_prop (state, "gotoAndStop"); - PUSH_OBJ (state); - push_string (state, s); - call (state, 1); - POP (state); -} - -static void -compile_goto_frame (CompileState *state, guint action, guint len) -{ - unsigned int i; - - i = swfdec_bits_get_u16 (state->bits); - compile_state_debug_add (state, "GotoFrame %u", i); - push_target (state); - push_prop (state, "gotoAndStop"); - PUSH_OBJ (state); - push_uint16 (state, i + 1); - call (state, 1); - POP (state); -} - -static void -compile_goto_frame2 (CompileState *state, guint action, guint len) -{ - int bias, play; - if (swfdec_bits_getbits (state->bits, 6)) { - SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0"); - } - bias = swfdec_bits_getbit (state->bits); - play = swfdec_bits_getbit (state->bits); - compile_state_debug_add (state, "GotoFrame2 %s", play ? "Play" : "Stop"); - if (bias) { - SWFDEC_ERROR ("scene bias not implemented"); - } - push_uint16 (state, 1); - push_target (state); - if (play) - push_prop (state, "gotoAndPlay"); - else - push_prop (state, "gotoAndStop"); - PUSH_OBJ (state); - FLASHCALL (state); -} - -static void -compile_wait_for_frame (CompileState *state, guint action, guint len) -{ - guint frame, jump; - guint8 command[3] = { JSOP_IFEQ, 0, 0 }; - - frame = swfdec_bits_get_u16 (state->bits); - jump = swfdec_bits_get_u8 (state->bits); - compile_state_debug_add (state, "WaitForFrame %u %u", frame, jump); - push_target (state); - push_prop (state, "_framesloaded"); - push_uint16 (state, frame); - GE (state); - compile_state_add_action_jump (state, jump, FALSE); - compile_state_add_code (state, command, 3); -} - -static void -compile_jump (CompileState *state, guint action, guint len) -{ - int amount = swfdec_bits_get_s16 (state->bits); - compile_state_debug_add (state, "Goto %d", amount); - DO_JUMP (state, JSOP_GOTO, amount + 5); -} - -static void -compile_if (CompileState *state, guint action, guint len) -{ - int amount = swfdec_bits_get_s16 (state->bits); - /* FIXME: Flash 4 does this differently */ - - compile_state_debug_add (state, "If %d", amount); - IFNE (state, amount + 5); -} - -static void -compile_set_target (CompileState *state, guint action, guint len) -{ - const char *s = swfdec_bits_skip_string (state->bits); - - compile_state_debug_add (state, "SetTarget \"%s\"", s); - THIS (state); - push_prop (state, "eval"); - PUSH_OBJ (state); - push_string (state, s); - call (state, 1); - compile_state_set_target (state); -} - -static void -compile_set_target_2 (CompileState *state, guint action, guint len) -{ - compile_state_set_target (state); -} - -static void -compile_constant_pool (CompileState *state, guint action, guint len) -{ - unsigned int i; - SwfdecBits *bits = state->bits; - - /* no debug info please */ - state->command_last = G_MAXUINT; - g_ptr_array_set_size (state->pool, swfdec_bits_get_u16 (bits)); - for (i = 0; i < state->pool->len; i++) { - g_ptr_array_index (state->pool, i) = (gpointer) swfdec_bits_skip_string (bits); - if (g_ptr_array_index (state->pool, i) == 0) { - compile_state_error (state, "Couldn't get string %u/%ufor constant pool", - i, state->pool->len); - return; - } - } -} - -static void -compile_get_url (CompileState *state, guint action, guint len) -{ - const char *target, *url; - - url = swfdec_bits_skip_string (state->bits); - target = swfdec_bits_skip_string (state->bits); - compile_state_debug_add (state, "GetURL \"%s\" \"%s\" ", url, target); - push_target (state); - push_prop (state, "getURL"); - PUSH_OBJ (state); - push_string (state, url); - push_string (state, target); - call (state, 2); - POP (state); -} - -static void -compile_oneliner_pop (CompileState *state, guint action, guint len) -{ - JSOp op; - switch (action) { - case 0x4f: - op = JSOP_SETELEM; - break; - default: - g_assert_not_reached (); - op = JSOP_NOP; - } - ONELINER (state, op); - POP (state); -} - -static void -compile_get_member (CompileState *state, guint action, guint len) -{ - add_try_catch_block (state, 1, 4); - ONELINER (state, JSOP_GETELEM); - THREELINER_INT (state, JSOP_GOTO, 5); - POP (state); - ONELINER (state, JSOP_VOID); -} - -/* Flash < 7 does conversions to numbers way different than JS or Flash 7+ - * This function is supposed to do that conversion */ -static void -ensure_number_flash6 (CompileState *state) -{ - if (state->version < 7) { - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 5); - POP (state); - ONELINER (state, JSOP_ZERO); - } -} - -/* Flash < 5 does not know numbers. Therefore we convert booleans to 1 or 0 */ -static void -boolean_to_number_flash4 (CompileState *state) -{ - if (state->version < 5) { - ONELINER (state, JSOP_ZERO); - ONELINER (state, JSOP_ADD); - } -} - -static void -compile_binary_op (CompileState *state, guint action, guint len) -{ - JSOp op; - - if (state->version < 7) { - /* lots of code to ensure that non-numeric arguments equal 0. */ - SWAP (state); - ensure_number_flash6 (state); - SWAP (state); - ensure_number_flash6 (state); - } - switch (action) { - case 0x0A: - op = JSOP_ADD; - break; - case 0x0B: - op = JSOP_SUB; - break; - case 0x0C: - op = JSOP_MUL; - break; - case 0x0D: - if (state->version >= 7) { - /* division by undefined isn't NaN, but +-Infinity */ - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 5); - POP (state); - ONELINER (state, JSOP_ZERO); - } - op = JSOP_DIV; - break; - default: - g_assert_not_reached (); - op = JSOP_NOP; - } - ONELINER (state, op); -} - -static void -compile_add2 (CompileState *state, guint action, guint len) -{ - if (state->version >= 7) { - ONELINER (state, JSOP_ADD); - return; - } - /* pop void arguments and ignore them - special case void + void = 0 */ - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 16); - POP (state); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 5); - POP (state); - ONELINER (state, JSOP_ZERO); - THREELINER_INT (state, JSOP_GOTO, 17); - SWAP (state); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 7); - POP (state); - THREELINER_INT (state, JSOP_GOTO, 5); - SWAP (state); - ONELINER (state, JSOP_ADD); -} - -static void -compile_less (CompileState *state, guint action, guint len) -{ - if (state->version < 7) { - /* lots of code to ensure that non-numeric arguments equal 0. */ - SWAP (state); - ensure_number_flash6 (state); - SWAP (state); - ensure_number_flash6 (state); - } - ONELINER (state, JSOP_LT); - - boolean_to_number_flash4 (state); -} - -static void -compile_comparison (CompileState *state, guint action, guint len) -{ - JSOp op; - - if (state->version < 7) { - /* lots of code to ensure that non-numeric arguments equal 0. */ - SWAP (state); - ensure_number_flash6 (state); - SWAP (state); - ensure_number_flash6 (state); - } else if (state->version == 7) { - /* Flash 7 returns undefined when one of the inputs is undefined */ - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 8); - POP (state); - ONELINER (state, JSOP_VOID); - THREELINER_INT (state, JSOP_GOTO, 18); - SWAP (state); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_DUP); - ONELINER (state, JSOP_VOID); - ONELINER (state, JSOP_EQ); - THREELINER_INT (state, JSOP_IFEQ, 8); - POP (state); - ONELINER (state, JSOP_VOID); - THREELINER_INT (state, JSOP_GOTO, 5); - SWAP (state); - } - /* FIXME: what about Flash > 7? */ - - switch (action) { - case 0x48: - op = JSOP_LT; - break; - case 0x67: - op = JSOP_GT; - break; - default: - g_assert_not_reached (); - op = JSOP_NOP; - } - ONELINER (state, op); -} - -static void -compile_oneliner (CompileState *state, guint action, guint len) -{ - JSOp op; - - switch (action) { - case 0x12: - op = JSOP_NOT; - break; - case 0x17: - op = JSOP_POP; - break; - case 0x47: - op = JSOP_ADD; - break; - case 0x49: - op = JSOP_NEW_EQ; - break; - case 0x4c: - op = JSOP_DUP; - break; - case 0x67: - op = JSOP_GT; - break; - default: - g_assert_not_reached (); - op = JSOP_NOP; - } - ONELINER (state, op); -} - -static void -compile_call_function (CompileState *state, guint action, guint len) -{ - push_target (state); - SWAP (state); - ONELINER (state, JSOP_GETELEM); - ONELINER (state, JSOP_PUSHOBJ); - ONELINER (state, JSOP_FLASHCALL); -} - -static void -compile_call_method (CompileState *state, guint action, guint len) -{ - add_try_catch_block (state, 1, 6); - ONELINER (state, JSOP_GETELEM); - ONELINER (state, JSOP_PUSHOBJ); -#if 0 - /* FIXME: can't add try/catch here, because FLASHCALL removes argument count from the stack (oops) */ - add_try_catch_block (state, 1, 5); -#endif - ONELINER (state, JSOP_FLASHCALL); - THREELINER_INT (state, JSOP_GOTO, 17); - /* exception handling goes here: clean up the stack */ - POP (state); - POP (state); - ONELINER (state, JSOP_DUP); - THREELINER_INT (state, JSOP_IFEQ, 10); - SWAP (state); - POP (state); - ONELINER (state, JSOP_ONE); - ONELINER (state, JSOP_SUB); - THREELINER_INT (state, JSOP_GOTO, -8); - ONELINER (state, JSOP_VOID); -} - -static void -compile_start_drag (CompileState *state, guint action, guint len) -{ - guint8 command[3] = { JSOP_IFEQ, 0, 27 }; - /* FIXME: target relative to this or target? */ - push_uint16 (state, 1); - push_target (state); - push_prop (state, "eval"); - PUSH_OBJ (state); - FLASHCALL (state); - FLASHSWAP (state, 3); - compile_state_add_code (state, command, 3); - FLASHSWAP (state, 3); - FLASHSWAP (state, 6); - FLASHSWAP (state, 3); - FLASHSWAP (state, 4); - FLASHSWAP (state, 5); - FLASHSWAP (state, 4); - push_uint16 (state, 5); - command[0] = JSOP_GOTO; - command[2] = 6; - compile_state_add_code (state, command, 3); - push_uint16 (state, 1); - SWAP (state); - FLASHSWAP (state, 3); - push_prop (state, "startDrag"); - PUSH_OBJ (state); - FLASHCALL (state); - POP (state); -} - -static void -compile_increment (CompileState *state, guint action, guint len) -{ - ONELINER (state, JSOP_ONE); - ONELINER (state, JSOP_ADD); -} - -static void -compile_decrement (CompileState *state, guint action, guint len) -{ - ONELINER (state, JSOP_ONE); - ONELINER (state, JSOP_SUB); -} - -static void -compile_random (CompileState *state, guint action, guint len) -{ - push_uint16 (state, 1); - bind_name (state, "random"); - push_prop (state, "random"); - PUSH_OBJ (state); - FLASHCALL (state); -} - -static void -compile_get_property (CompileState *state, guint action, guint len) -{ - SWAP (state); - push_uint16 (state, 2); - push_target (state); - push_prop (state, "getProperty"); - PUSH_OBJ (state); - FLASHCALL (state); -} - -static void -compile_set_property (CompileState *state, guint action, guint len) -{ - FLASHSWAP (state, 3); - push_uint16 (state, 3); - bind_name (state, "setProperty"); - push_prop (state, "setProperty"); - PUSH_OBJ (state); - FLASHCALL (state); - POP (state); -} - -static void -compile_string_add (CompileState *state, guint action, guint len) -{ - /* be sure to have strings */ - push_string (state, ""); - ONELINER (state, JSOP_ADD); - ONELINER (state, JSOP_ADD); -} - -static void -compile_equals (CompileState *state, guint action, guint len) -{ - /* ensure we compare numbers */ - ONELINER (state, JSOP_POS); - ONELINER (state, JSOP_EQ); - if (state->version <= 4) { - /* FLash 4 wants 1 or 0 on the stack instead of TRUE or FALSE */ - ONELINER (state, JSOP_ZERO); - ONELINER (state, JSOP_BITOR); - } -} - -static void -compile_to_integer (CompileState *state, guint action, guint len) -{ - /* There's no opcode so we use a bitwise operation that forces a conversion */ - ONELINER (state, JSOP_ZERO); - ONELINER (state, JSOP_BITOR); -} - -static void -compile_target_path (CompileState *state, guint action, guint len) -{ - ONELINER (state, JSOP_DUP); - name (state, "MovieClip"); - ONELINER (state, JSOP_INSTANCEOF); - THREELINER_INT (state, JSOP_IFEQ, 13); - push_prop (state, "toString"); - PUSH_OBJ (state); - call (state, 0); - THREELINER_INT (state, JSOP_GOTO, 4); - ONELINER (state, JSOP_VOID); -} - -static void -compile_new_object (CompileState *state, guint action, guint len) -{ - /* use eval to get at the constructor - spidermonkey doesn't like - * new with strings */ - push_uint16 (state, 1); - bind_name (state, "eval"); - push_prop (state, "eval"); - PUSH_OBJ (state); - FLASHCALL (state); - /* use call instead of new here - if this doesn't work, a FLASHNEW opcode is needed */ - PUSH_OBJ (state); - FLASHCALL (state); -} - -static void -compile_init_object (CompileState *state, guint action, guint len) -{ - name (state, "Object"); - PUSH_OBJ (state); - THREELINER_INT (state, JSOP_NEW, 0); - DUP (state); - FLASHSWAP (state, 3); - DUP (state); - THREELINER_INT (state, JSOP_IFEQ, 17); - ONELINER (state, JSOP_ONE); - ONELINER (state, JSOP_SUB); - FLASHSWAP (state, 5); - SWAP (state); - FLASHSWAP (state, 4); - ONELINER (state, JSOP_SETELEM); - POP (state); - THREELINER_INT (state, JSOP_GOTO, -19); - POP (state); - POP (state); -} - -static void -compile_simple_bind_call (CompileState *state, guint action, guint len) -{ - char *name; - switch (action) { - case 0x09: - name = "stopAllSounds"; - break; - default: - g_assert_not_reached (); - return; - } - bind_name (state, name); - call_void_function (state, name); -} - -static void -compile_simple_call (CompileState *state, guint action, guint len) -{ - char *name; - - /* FIXME: shouldn't some functions here PUSH_OBJ instead of push_target? */ - push_target (state); - switch (action) { - case 0x04: - name = "nextFrame"; - break; - case 0x05: - name = "prevFrame"; - break; - case 0x06: - name = "play"; - break; - case 0x07: - name = "stop"; - break; - case 0x09: - name = "stopAllSounds"; - break; - case 0x28: - name = "stopDrag"; - break; - default: - g_assert_not_reached (); - return; - } - call_void_function (state, name); -} - -/*** COMPILER ***/ - -typedef struct { - guint action; - const char *name; - void (* compile) (CompileState *state, guint action, guint len); -} SwfdecActionSpec; - -static const SwfdecActionSpec * swfdec_action_find (guint action); - -/** - * swfdec_compile: - * @player: a #SwfdecPlayer - * @bits: the data to read - * @version: ActionScript version to compile for - * @name: name describing the script or NULL - * - * parses the data pointed to by @bits and compiles the ActionScript commands - * encountered into a script for later execution. - * - * Returns: A new JSScript or NULL on failure - **/ -JSScript * -swfdec_compile (SwfdecPlayer *player, SwfdecBits *bits, int version, const char *name) -{ - unsigned int action, len; - const SwfdecActionSpec *current; - CompileState state; - JSScript *ret; -#ifndef SWFDEC_DISABLE_DEBUG - unsigned char *start = bits->ptr; -#endif -#ifndef G_DISABLE_ASSERT - unsigned char *target; -#endif -//#define SWFDEC_DUMP_SCRIPTS -#ifdef SWFDEC_DUMP_SCRIPTS - SwfdecBits dump = *bits; -#endif - - g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL); - g_return_val_if_fail (bits != NULL, NULL); - - if (name == NULL) - name = "Unnamed script"; - compile_state_init (player->jscx, bits, version, &state); - SWFDEC_INFO ("Creating new script in frame"); - while (swfdec_bits_left (bits) && (action = swfdec_bits_get_u8 (bits))) { - if (action & 0x80) { - len = swfdec_bits_get_u16 (bits); - } else { - len = 0; - } - if (swfdec_bits_left (bits) < len * 8) { - compile_state_error (&state, "Not enough data available to parse next action"); - } -#ifndef G_DISABLE_ASSERT - target = bits->ptr + len; -#endif - current = swfdec_action_find (action); - SWFDEC_LOG ("compiling action %d %s (len %d, total %d)", action, - current ? current->name : "unknown", len > 0 ? 3 + len : 1, - bits->ptr - start); -#if 0 - if (state.error == NULL) - g_print (" compiling action %d %s (len %d, total %d)\n", action, - current ? current->name : "unknown", len > 0 ? 3 + len : 1, - bits->ptr - start); -#endif - if (state.error == NULL && current && current->compile) { - state.command_last = state.bytecode->len; - current->compile (&state, action, len); - compile_state_debug_add_default (&state, action, current->name); - compile_state_push_offset (&state, len ? 3 + len : 1); -#ifndef G_DISABLE_ASSERT - if (target != bits->ptr) { - SWFDEC_ERROR ("parsed length and supposed length differ by %d bytes in %s action", - bits->ptr - target, current->name); - } - bits->ptr = target; -#endif - } else { - swfdec_bits_getbits (bits, len * 8); - if (state.error == NULL) { - if (current) { - compile_state_error (&state, "No compilation function for %s action", current->name); - } else { - compile_state_error (&state, "unknown action 0x%02X", action); - } - } - } - } - ret = compile_state_finish (&state, player, name); -#if 0 - if (ret) - swfdec_disassemble (s, ret); -#endif -#ifdef SWFDEC_DUMP_SCRIPTS - { - static int dump_count = 0; - char *filename = g_strdup_printf ("script%d", dump_count++); - g_file_set_contents (filename, (char *) dump.ptr, bits->ptr - dump.ptr, NULL); - g_free (filename); - } -#endif - - return ret; -} - -/** - * swfdec_compiler_destroy_script: - * @player: a #SwfdecPlayer - * @script: a JSScript created via swfdec_compile() - * - * Destroys a script that was previously created via swfdec_compile () for @player. - * All scripts created via swfdec_compile must be removed with this function. - **/ -void -swfdec_compiler_destroy_script (SwfdecPlayer *player, JSScript *script) -{ - g_return_if_fail (SWFDEC_IS_PLAYER (player)); - g_return_if_fail (script != NULL); - - if (SWFDEC_IS_DEBUGGER (player)) - swfdec_debugger_remove_script (SWFDEC_DEBUGGER (player), script); - JS_DestroyScript (player->jscx, script); -} - -/* must be sorted! */ -SwfdecActionSpec actions[] = { - /* version 3 */ - { 0x04, "NextFrame", compile_simple_call }, - { 0x05, "PreviousFrame", compile_simple_call }, - { 0x06, "Play", compile_simple_call }, - { 0x07, "Stop", compile_simple_call }, - { 0x08, "ToggleQuality", NULL }, - { 0x09, "StopSounds", compile_simple_bind_call }, - /* version 4 */ - { 0x0a, "Add", compile_binary_op }, - { 0x0b, "Subtract", compile_binary_op }, - { 0x0c, "Multiply", compile_binary_op }, - { 0x0d, "Divide", compile_binary_op }, - { 0x0e, "Equals", compile_equals }, - { 0x0f, "Less", compile_less }, - { 0x10, "And", NULL }, - { 0x11, "Or", NULL }, - { 0x12, "Not", compile_oneliner }, - { 0x13, "StringEquals", NULL }, - { 0x14, "StringLength", NULL }, - { 0x15, "StringExtract", NULL }, - { 0x17, "Pop", compile_oneliner }, - { 0x18, "ToInteger", compile_to_integer }, - { 0x1c, "GetVariable", compile_get_variable }, - { 0x1d, "SetVariable", compile_set_variable }, - { 0x20, "SetTarget2", compile_set_target_2 }, - { 0x21, "StringAdd", compile_string_add }, - { 0x22, "GetProperty", compile_get_property }, - { 0x23, "SetProperty", compile_set_property }, - { 0x24, "CloneSprite", NULL }, - { 0x25, "RemoveSprite", NULL }, - { 0x26, "Trace", compile_trace }, - { 0x27, "StartDrag", compile_start_drag }, - { 0x28, "EndDrag", compile_simple_call }, - { 0x29, "StringLess", NULL }, - /* version 7 */ - { 0x2a, "Throw", NULL }, - { 0x2b, "Cast", NULL }, - { 0x2c, "Implements", NULL }, - /* version 4 */ - { 0x30, "RandomNumber", compile_random }, - { 0x31, "MBStringLength", NULL }, - { 0x32, "CharToAscii", NULL }, - { 0x33, "AsciiToChar", NULL }, - { 0x34, "GetTime", NULL }, - { 0x35, "MBStringExtract", NULL }, - { 0x36, "MBCharToAscii", NULL }, - { 0x37, "MVAsciiToChar", NULL }, - /* version 5 */ - { 0x3a, "Delete", NULL }, - { 0x3b, "Delete2", NULL }, - { 0x3c, "DefineLocal", NULL }, - { 0x3d, "CallFunction", compile_call_function }, - { 0x3e, "Return", NULL }, - { 0x3f, "Modulo", NULL }, - { 0x40, "NewObject", compile_new_object }, - { 0x41, "DefineLocal2", NULL }, - { 0x42, "InitArray", NULL }, - { 0x43, "InitObject", compile_init_object }, - { 0x44, "Typeof", NULL }, - { 0x45, "TargetPath", compile_target_path }, - { 0x46, "Enumerate", NULL }, - { 0x47, "Add2", compile_add2 }, - { 0x48, "Less2", compile_comparison }, - { 0x49, "Equals2", compile_oneliner }, - { 0x4a, "ToNumber", NULL }, - { 0x4b, "ToString", NULL }, - { 0x4c, "PushDuplicate", compile_oneliner }, - { 0x4d, "Swap", NULL }, - { 0x4e, "GetMember", compile_get_member }, - { 0x4f, "SetMember", compile_oneliner_pop }, /* apparently the result is ignored */ - { 0x50, "Increment", compile_increment }, - { 0x51, "Decrement", compile_decrement }, - { 0x52, "CallMethod", compile_call_method }, - { 0x53, "NewMethod", NULL }, - /* version 6 */ - { 0x54, "InstanceOf", NULL }, - { 0x55, "Enumerate2", NULL }, - /* version 5 */ - { 0x60, "BitAnd", NULL }, - { 0x61, "BitOr", NULL }, - { 0x62, "BitXor", NULL }, - { 0x63, "BitLShift", NULL }, - { 0x64, "BitRShift", NULL }, - { 0x65, "BitURShift", NULL }, - /* version 6 */ - { 0x66, "StrictEquals", NULL }, - { 0x67, "Greater", compile_comparison }, - { 0x68, "StringGreater", NULL }, - /* version 7 */ - { 0x69, "Extends", NULL }, - - /* version 3 */ - { 0x81, "GotoFrame", compile_goto_frame }, - { 0x83, "GetURL", compile_get_url }, - /* version 5 */ - { 0x87, "StoreRegister", NULL }, - { 0x88, "ConstantPool", compile_constant_pool }, - /* version 3 */ - { 0x8a, "WaitForFrame", compile_wait_for_frame }, - { 0x8b, "SetTarget", compile_set_target }, - { 0x8c, "GotoLabel", compile_goto_label }, - /* version 4 */ - { 0x8d, "WaitForFrame2", NULL }, - /* version 7 */ - { 0x8e, "DefineFunction2", NULL }, - { 0x8f, "Try", NULL }, - /* version 5 */ - { 0x94, "With", NULL }, - /* version 4 */ - { 0x96, "Push", compile_push }, - { 0x99, "Jump", compile_jump }, - { 0x9a, "GetURL2", NULL }, - /* version 5 */ - { 0x9b, "DefineFunction", NULL }, - /* version 4 */ - { 0x9d, "If", compile_if }, - { 0x9e, "Call", NULL }, - { 0x9f, "GotoFrame2", compile_goto_frame2 } -}; - -int -uint_compare (gconstpointer v1, gconstpointer v2) -{ - return *((const unsigned int*) v1) - *((const unsigned int*) v2); -} - -static const SwfdecActionSpec * -swfdec_action_find (guint action) -{ - return bsearch (&action, actions, G_N_ELEMENTS (actions), - sizeof (SwfdecActionSpec), uint_compare); -} diff --git a/libswfdec/swfdec_compiler.h b/libswfdec/swfdec_compiler.h deleted file mode 100644 index d3b8c9c..0000000 --- a/libswfdec/swfdec_compiler.h +++ /dev/null @@ -1,21 +0,0 @@ - -#ifndef __SWFDEC_COMPILER_H__ -#define __SWFDEC_COMPILER_H__ - -#include <libswfdec/js/jsapi.h> -#include <libswfdec/swfdec_bits.h> -#include <libswfdec/swfdec_player.h> - -#error "swfdec_compiler.h is out of the game now!" -G_BEGIN_DECLS - -JSScript * swfdec_compile (SwfdecPlayer * player, - SwfdecBits * bits, - int version, - const char * name); -void swfdec_compiler_destroy_script (SwfdecPlayer * player, - JSScript * script); - -G_END_DECLS - -#endif diff-tree 375b6d4dc5d4335c3fcafa0ce96076287ae2b9ac (from parents) Merge: a86c50354559053bfdba86f13cdf8ec9c455205a bdc67ff4e611ed187083eb9a45db630eecb260dd Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 12:20:07 2007 +0100 Merge branch 'master' into interpreter diff --cc test/Makefile.am index 33a647c,e0957af..00c8203 @@@ -1,10 -1,6 +1,10 @@@ - SUBDIRS = sound trace various + SUBDIRS = image sound trace various -noinst_PROGRAMS = swfdec-extract dump parse +if WITH_GTK +noinst_PROGRAMS = swfdec-extract dump parse swfedit +else +noinst_PROGRAMS = swfdec-extract dump parse +endif dump_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js dump_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS) diff-tree a86c50354559053bfdba86f13cdf8ec9c455205a (from parents) Merge: 940ef9614313d253bb9282e26f48968b4af13c85 d7db95f092791ed1e81ad2d2e4f9e3fb345d6f79 Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 18:39:22 2007 +0100 Merge branch 'master' into interpreter Conflicts: libswfdec/swfdec_image.c diff --cc libswfdec/swfdec_bits.c index f3ea7c4,5013e49..21172f2 @@@ -482,13 -450,13 +482,13 @@@ g = swfdec_bits_get_u8 (bits); b = swfdec_bits_get_u8 (bits); - return SWF_COLOR_COMBINE (r, g, b, 0xff); + return SWFDEC_COLOR_COMBINE (r, g, b, 0xff); } -unsigned int +SwfdecColor swfdec_bits_get_rgba (SwfdecBits * bits) { - int r, g, b, a; + unsigned int r, g, b, a; r = swfdec_bits_get_u8 (bits); g = swfdec_bits_get_u8 (bits); diff --cc libswfdec/swfdec_image.c index 23602c4,224e101..53dad98 @@@ -290,18 -288,19 +267,17 @@@ swfdec_image_jpeg3_load (SwfdecImage *image) { JpegRGBDecoder *dec; - unsigned char *image_data; unsigned char *alpha_data; SwfdecBits bits; - int len; + SwfdecBuffer *buffer; int jpeg_length; - bits.buffer = image->raw_data; - bits.ptr = image->raw_data->data; - bits.idx = 0; - bits.end = bits.ptr + image->raw_data->length; - - bits.ptr += 2; + swfdec_bits_init (&bits, image->raw_data); jpeg_length = swfdec_bits_get_u32 (&bits); + buffer = swfdec_bits_get_buffer (&bits, jpeg_length); + if (buffer == NULL) + return; dec = jpeg_rgb_decoder_new (); @@@ -318,15 -316,13 +294,13 @@@ &image->rowstride, &image->width, &image->height); jpeg_rgb_decoder_free (dec); - bits.ptr += jpeg_length; - - alpha_data = lossless (bits.ptr, bits.end - bits.ptr, &len); + buffer = swfdec_bits_get_buffer (&bits, -1); + alpha_data = lossless (buffer->data, buffer->length, image->width * image->height); + swfdec_buffer_unref (buffer); - merge_alpha (image, image_data, alpha_data); + merge_alpha (image, image->data, alpha_data); g_free (alpha_data); - swfdec_image_create_surface (image, image_data); - SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); } @@@ -356,13 -348,20 +326,12 @@@ swfdec_image_lossless_load (SwfdecImage *image) { int format; - int color_table_size; + guint color_table_size; unsigned char *ptr; - int len; - unsigned char *endptr; SwfdecBits bits; - unsigned char *image_data = NULL; int have_alpha = (image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2); - bits.buffer = image->raw_data; - bits.ptr = image->raw_data->data; - bits.idx = 0; - bits.end = bits.ptr + image->raw_data->length; - endptr = bits.ptr + bits.buffer->length; - - bits.ptr += 2; + swfdec_bits_init (&bits, image->raw_data); format = swfdec_bits_get_u8 (&bits); SWFDEC_LOG (" format = %d", format); @@@ -384,29 -383,31 +353,29 @@@ if (image->width == 0 || image->height == 0) return; swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height); - ptr = lossless (bits.ptr, endptr - bits.ptr, &len); - bits.ptr = endptr; if (format == 3) { - unsigned char *color_table; unsigned char *indexed_data; - int i; + guint i; + unsigned int rowstride = (image->width + 3) & ~3; - image_data = g_malloc (4 * image->width * image->height); + image->data = g_malloc (4 * image->width * image->height); image->rowstride = image->width * 4; - color_table = g_malloc (color_table_size * 4); - if (have_alpha) { + ptr = lossless (bits.ptr, bits.end - bits.ptr, + color_table_size * 4 + rowstride * image->height); for (i = 0; i < color_table_size; i++) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN - color_table[i * 4 + 0] = ptr[i * 4 + 2]; - color_table[i * 4 + 1] = ptr[i * 4 + 1]; - color_table[i * 4 + 2] = ptr[i * 4 + 0]; - color_table[i * 4 + 3] = ptr[i * 4 + 3]; + guint8 tmp = ptr[i * 4 + 0]; + ptr[i * 4 + 0] = ptr[i * 4 + 2]; + ptr[i * 4 + 2] = tmp; #else - color_table[i * 4 + 0] = ptr[i * 4 + 3]; - color_table[i * 4 + 1] = ptr[i * 4 + 0]; - color_table[i * 4 + 2] = ptr[i * 4 + 1]; - color_table[i * 4 + 3] = ptr[i * 4 + 2]; + guint8 tmp = ptr[i * 4 + 3]; + ptr[i * 4 + 3] = ptr[i * 4 + 2]; + ptr[i * 4 + 2] = ptr[i * 4 + 1]; + ptr[i * 4 + 1] = ptr[i * 4 + 0]; + ptr[i * 4 + 0] = tmp; #endif } indexed_data = ptr + color_table_size * 4; @@@ -432,70 -427,55 +401,51 @@@ } indexed_data = ptr + color_table_size * 3; } - swfdec_image_colormap_decode (image, image_data, indexed_data, + swfdec_image_colormap_decode (image, image->data, indexed_data, - color_table, color_table_size); + ptr, color_table_size); - g_free (color_table); g_free (ptr); -- } -- if (format == 4) { - unsigned char *p = ptr; ++ } else if (format == 4) { int i, j; unsigned int c; unsigned char *idata; ++ guint8 *p; if (have_alpha) { SWFDEC_INFO("16bit images aren't allowed to have alpha, ignoring"); have_alpha = FALSE; } - ptr = lossless (bits.ptr, bits.end - bits.ptr, 2 * image->width * image->height); - image_data = g_malloc (4 * image->width * image->height); - idata = image_data; ++ p = ptr = lossless (bits.ptr, bits.end - bits.ptr, 2 * image->width * image->height); + image->data = g_malloc (4 * image->width * image->height); + idata = image->data; image->rowstride = image->width * 4; /* 15 bit packed */ for (j = 0; j < image->height; j++) { for (i = 0; i < image->width; i++) { - c = ptr[1] | (ptr[0] << 8); - #if G_BYTE_ORDER == G_LITTLE_ENDIAN - idata[0] = (c << 3) | ((c >> 2) & 0x7); - idata[1] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); - idata[2] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); - idata[3] = 0xff; - #else - idata[3] = (c << 3) | ((c >> 2) & 0x7); - idata[2] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); - idata[1] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); - idata[0] = 0xff; - #endif + c = p[1] | (p[0] << 8); + idata[SWFDEC_COLOR_INDEX_BLUE] = (c << 3) | ((c >> 2) & 0x7); + idata[SWFDEC_COLOR_INDEX_GREEN] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); + idata[SWFDEC_COLOR_INDEX_RED] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); + idata[SWFDEC_COLOR_INDEX_ALPHA] = 0xff; - p += 2; + ptr += 2; idata += 4; } } g_free (ptr); } if (format == 5) { - - image_data = lossless (bits.ptr, bits.end - bits.ptr, 4 * image->width * image->height); - image->rowstride = image->width * 4; - - #if G_BYTE_ORDER == G_LITTLE_ENDIAN - { - int i, j; - /* image is stored in 0RGB format. We use ARGB/BGRA. */ - for (j = 0; j < image->height; j++) { - for (i = 0; i < image->width; i++) { - ptr[0] = ptr[3]; - ptr[1] = ptr[2]; - ptr[2] = ptr[1]; - ptr[3] = 255; - ptr += 4; - } + int i, j; - - image->data = ptr; - image->rowstride = image->width * 4; - ++ ptr = image->data = lossless (bits.ptr, bits.end - bits.ptr, 4 * image->width * image->height); + /* image is stored in 0RGB format. We use ARGB/BGRA. */ + for (j = 0; j < image->height; j++) { + for (i = 0; i < image->width; i++) { + *((guint32 *) ptr) = GUINT32_FROM_BE (*((guint32 *) ptr)); + ptr += 4; } } - #endif } - - swfdec_image_create_surface (image, image_data); } int diff --cc test/dump.c index 9ee0524,9ee0524..efddeee @@@ -1,7 -1,7 +1,7 @@@ /* Swfdec * Copyright (C) 2003-2006 David Schleef <ds@schleef.org> * 2005-2006 Eric Anholt <eric@anholt.net> -- * 2006 Benjamin Otte <otte@gnome.org> ++ * 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@@ -34,6 -34,6 +34,7 @@@ #include <libswfdec/swfdec_button.h> #include <libswfdec/swfdec_edittext.h> #include <libswfdec/swfdec_font.h> ++#include <libswfdec/swfdec_image.h> #include <libswfdec/swfdec_movie.h> #include <libswfdec/swfdec_player_internal.h> #include <libswfdec/swfdec_root_movie.h> @@@ -287,6 -287,6 +288,34 @@@ } } ++const char * ++get_image_type_name (SwfdecImageType type) ++{ ++ switch (type) { ++ case SWFDEC_IMAGE_TYPE_JPEG: ++ return "JPEG with global table"; ++ case SWFDEC_IMAGE_TYPE_JPEG2: ++ return "JPEG"; ++ case SWFDEC_IMAGE_TYPE_JPEG3: ++ return "JPEG with alpha"; ++ case SWFDEC_IMAGE_TYPE_LOSSLESS: ++ return "lossless"; ++ case SWFDEC_IMAGE_TYPE_LOSSLESS2: ++ return "lossless with alpha"; ++ default: ++ g_assert_not_reached (); ++ return "Unknown"; ++ } ++} ++ ++static void ++dump_image (SwfdecImage *image) ++{ ++ cairo_surface_destroy (swfdec_image_create_surface (image)); ++ g_print (" %s %u x %u\n", get_image_type_name (image->type), ++ image->width, image->height); ++} ++ static void dump_objects (SwfdecSwfDecoder *s) { @@@ -301,6 -301,6 +330,9 @@@ g_print (" extents: %g %g %g %g\n", graphic->extents.x0, graphic->extents.y0, graphic->extents.x1, graphic->extents.y1); } ++ if (SWFDEC_IS_IMAGE (c)) { ++ dump_image (SWFDEC_IMAGE (c)); ++ } if (SWFDEC_IS_SPRITE (c)) { dump_sprite (SWFDEC_SPRITE (c)); } diff --cc test/swfdec-extract.c index ac79124,b4a2951..47e8234 @@@ -258,8 -269,11 +269,11 @@@ } else if (SWFDEC_IS_GRAPHIC (character)) { if (!export_graphic (SWFDEC_GRAPHIC (character), argv[3])) ret = 1; + } else if (SWFDEC_IS_IMAGE (character)) { + if (!export_image (SWFDEC_IMAGE (character), argv[3])) + ret = 1; } else { - g_printerr ("id %ld does not specify an exportable object", id); + g_printerr ("id %ld does not specify an exportable object\n", id); ret = 1; } diff --cc test/swfdec_out.c index bf7aa9e,0000000..0719b0f mode 100644,000000..100644 @@@ -1,258 -1,0 +1,258 @@@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "swfdec_out.h" + +SwfdecOut * +swfdec_out_open (void) +{ + SwfdecOut *out = g_new0 (SwfdecOut, 1); + + out->data = g_malloc (SWFDEC_OUT_INITIAL); + out->ptr = out->data; + out->end = out->data + SWFDEC_OUT_INITIAL; + + return out; +} + +static void +swfdec_out_syncbits (SwfdecOut *out) +{ + g_return_if_fail (out != NULL); + + if (out->idx > 0) { + out->ptr++; + out->idx = 0; + } +} + +SwfdecBuffer * +swfdec_out_close (SwfdecOut *out) +{ + SwfdecBuffer *buffer; + + g_return_val_if_fail (out != NULL, NULL); + + swfdec_out_syncbits (out); + + buffer = swfdec_buffer_new (); + buffer->data = out->data; + buffer->length = out->ptr - out->data; + + g_free (out); + + return buffer; +} + +unsigned int +swfdec_out_left (SwfdecOut *out) +{ + g_return_val_if_fail (out != NULL, 0); + + return (out->end - out->ptr) * 8 - out->idx; +} + +void +swfdec_out_ensure_bits (SwfdecOut *out, unsigned int bits) +{ + unsigned int current, taken, needed; + + g_return_if_fail (out != NULL); + + current = swfdec_out_left (out); + if (current >= bits) + return; + taken = out->ptr - out->data; + needed = (bits - current + 7) / 8; + needed += SWFDEC_OUT_STEP; + needed -= needed % SWFDEC_OUT_STEP; + needed += out->end - out->data; + out->data = g_realloc (out->data, needed); + out->ptr = out->data + taken; + out->end = out->data + needed; +} + +void +swfdec_out_prepare_bytes (SwfdecOut *out, unsigned int bytes) +{ + g_return_if_fail (out != NULL); + + swfdec_out_syncbits (out); + swfdec_out_ensure_bits (out, bytes * 8); +} + +void +swfdec_out_put_buffer (SwfdecOut *out, SwfdecBuffer *buffer) +{ + g_return_if_fail (out != NULL); + + swfdec_out_prepare_bytes (out, buffer->length); + memcpy (out->ptr, buffer->data, buffer->length); + out->ptr += buffer->length; +} + +void +swfdec_out_put_u8 (SwfdecOut *out, guint i) +{ + g_return_if_fail (i <= G_MAXUINT8); + + swfdec_out_prepare_bytes (out, 1); + *out->ptr = i; + out->ptr++; +} + +void +swfdec_out_put_u16 (SwfdecOut *out, guint i) +{ + g_return_if_fail (i <= G_MAXUINT16); + + swfdec_out_prepare_bytes (out, 2); + *(guint16 *)out->ptr = GUINT16_TO_LE (i); + out->ptr += 2; +} + +void +swfdec_out_put_u32 (SwfdecOut *out, guint i) +{ + g_return_if_fail (i <= G_MAXUINT32); + + swfdec_out_prepare_bytes (out, 4); + *(guint32 *)out->ptr = GUINT32_TO_LE (i); + out->ptr += 4; +} + +void +swfdec_out_put_bit (SwfdecOut *out, gboolean bit) +{ + g_return_if_fail (out != NULL); + + swfdec_out_put_bits (out, bit ? 1 : 0, 1); +} + +void +swfdec_out_put_bits (SwfdecOut *out, guint bits, guint n_bits) +{ + g_return_if_fail (out != NULL); + + swfdec_out_ensure_bits (out, n_bits); + + /* FIXME: implement this less braindead */ + while (n_bits) { + guint bits_now = MIN (n_bits, 8 - out->idx); + guint value = bits >> (n_bits - bits_now); + + /* clear data if necessary */ + if (out->idx == 0) + *out->ptr = 0; + value &= (1 << bits_now) - 1; + value <<= 8 - out->idx - bits_now; + *out->ptr |= value; + out->idx += bits_now; + g_assert (out->idx <= 8); + if (out->idx == 8) { + out->ptr ++; + out->idx = 0; + } + n_bits -= bits_now; + } +} + +void +swfdec_out_put_sbits (SwfdecOut *out, int bits, guint n_bits) +{ + g_return_if_fail (out != NULL); + swfdec_out_put_bits (out, bits, n_bits); +} + +static guint +swfdec_out_bits_required (guint x) +{ + guint ret = 0; + + while (x > 0) { + x >>= 1; + ret++; + } + return ret; +} + +static guint +swfdec_out_sbits_required (int x) +{ + if (x < 0) + x = -x; + return swfdec_out_bits_required (x) + 1; +} + +void +swfdec_out_put_rect (SwfdecOut *out, SwfdecRect *rect) +{ + int x0, x1, y0, y1; + guint req, tmp; + + g_return_if_fail (out != NULL); + g_return_if_fail (rect != NULL); + + x0 = rect->x0; + y0 = rect->y0; + x1 = rect->x1; + y1 = rect->y1; + req = swfdec_out_sbits_required (x0); + tmp = swfdec_out_sbits_required (y0); + req = MAX (req, tmp); + tmp = swfdec_out_sbits_required (x1); + req = MAX (req, tmp); + tmp = swfdec_out_sbits_required (y1); + req = MAX (req, tmp); + swfdec_out_syncbits (out); + swfdec_out_put_bits (out, req, 5); + swfdec_out_put_sbits (out, x0, req); + swfdec_out_put_sbits (out, x1, req); + swfdec_out_put_sbits (out, y0, req); + swfdec_out_put_sbits (out, y1, req); + swfdec_out_syncbits (out); +} + +void +swfdec_out_put_rgb (SwfdecOut *out, SwfdecColor color) +{ + g_return_if_fail (out != NULL); + - swfdec_out_put_u8 (out, SWF_COLOR_R (color)); - swfdec_out_put_u8 (out, SWF_COLOR_G (color)); - swfdec_out_put_u8 (out, SWF_COLOR_B (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_R (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_G (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_B (color)); +} + +void +swfdec_out_put_rgba (SwfdecOut *out, SwfdecColor color) +{ + g_return_if_fail (out != NULL); + - swfdec_out_put_u8 (out, SWF_COLOR_R (color)); - swfdec_out_put_u8 (out, SWF_COLOR_G (color)); - swfdec_out_put_u8 (out, SWF_COLOR_B (color)); - swfdec_out_put_u8 (out, SWF_COLOR_A (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_R (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_G (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_B (color)); ++ swfdec_out_put_u8 (out, SWFDEC_COLOR_A (color)); +} + diff --cc test/swfedit_token.c index 8c8b075,0000000..f3f2bcc mode 100644,000000..100644 @@@ -1,573 -1,0 +1,573 @@@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, to_string to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <gtk/gtk.h> +#include <libswfdec/swfdec_buffer.h> +#include <libswfdec/swfdec_color.h> +#include "swfedit_token.h" + +/*** CONVERTERS ***/ + +static gboolean +swfedit_parse_hex (const char *s, guint *result) +{ + guint byte; + + if (s[0] >= '0' && s[0] <= '9') + byte = s[0] - '0'; + else if (s[0] >= 'a' && s[0] <= 'f') + byte = s[0] + 10 - 'a'; + else if (s[0] >= 'A' && s[0] <= 'F') + byte = s[0] + 10 - 'A'; + else + return FALSE; + s++; + byte *= 16; + if (s[0] >= '0' && s[0] <= '9') + byte += s[0] - '0'; + else if (s[0] >= 'a' && s[0] <= 'f') + byte += s[0] + 10 - 'a'; + else if (s[0] >= 'A' && s[0] <= 'F') + byte += s[0] + 10 - 'A'; + else + return FALSE; + *result = byte; + return TRUE; +} + +static gboolean +swfedit_binary_from_string (const char *s, gpointer* result) +{ + GByteArray *array = g_byte_array_new (); + guint byte; + guint8 add; + + while (g_ascii_isspace (*s)) s++; + do { + if (!swfedit_parse_hex (s, &byte)) + break; + s += 2; + add = byte; + g_byte_array_append (array, &add, 1); + while (g_ascii_isspace (*s)) s++; + } while (*s != '\0'); + if (*s == '\0') { + SwfdecBuffer *buffer = swfdec_buffer_new (); + buffer->length = array->len; + buffer->data = array->data; + g_byte_array_free (array, FALSE); + *result = buffer; + return TRUE; + } + g_byte_array_free (array, TRUE); + return FALSE; +} + +static char * +swfedit_binary_to_string (gconstpointer value) +{ + guint i; + const SwfdecBuffer *buffer = value; + GString *string = g_string_new (""); + + for (i = 0; i < buffer->length; i++) { + if (i && i % 4 == 0) + g_string_append_c (string, ' '); + g_string_append_printf (string, "%02X", buffer->data[i]); + } + return g_string_free (string, FALSE); +} + +static gboolean +swfedit_from_string_unsigned (const char *s, gulong max, gpointer* result) +{ + char *end; + gulong u; + + g_assert (max <= G_MAXUINT); + u = strtoul (s, &end, 10); + if (*end != '\0') + return FALSE; + if (u > max) + return FALSE; + *result = GUINT_TO_POINTER (u); + return TRUE; +} + +static gboolean +swfedit_uint8_from_string (const char *s, gpointer* result) +{ + return swfedit_from_string_unsigned (s, G_MAXUINT8, result); +} + +static gboolean +swfedit_uint16_from_string (const char *s, gpointer* result) +{ + return swfedit_from_string_unsigned (s, G_MAXUINT16, result); +} + +static gboolean +swfedit_uint32_from_string (const char *s, gpointer* result) +{ + return swfedit_from_string_unsigned (s, G_MAXUINT32, result); +} + +static char * +swfedit_to_string_unsigned (gconstpointer value) +{ + return g_strdup_printf ("%u", GPOINTER_TO_UINT (value)); +} + +static gboolean +swfedit_rect_from_string (const char *s, gpointer* result) +{ + return FALSE; +} + +static char * +swfedit_rect_to_string (gconstpointer value) +{ + const SwfdecRect *rect = value; + + return g_strdup_printf ("%d, %d, %d, %d", (int) rect->x0, (int) rect->y0, + (int) rect->x1, (int) rect->y1); +} + +static gboolean +swfedit_rgb_from_string (const char *s, gpointer* result) +{ + guint r, g, b; + if (strlen (s) != 6) + return FALSE; + if (!swfedit_parse_hex (s, &r)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &g)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &b)) + return FALSE; - *result = GUINT_TO_POINTER (SWF_COLOR_COMBINE (r, g, b, 0xFF)); ++ *result = GUINT_TO_POINTER (SWFDEC_COLOR_COMBINE (r, g, b, 0xFF)); + return TRUE; +} + +static char * +swfedit_rgb_to_string (gconstpointer value) +{ + guint c = GPOINTER_TO_UINT (value); + - return g_strdup_printf ("%02X%02X%02X", SWF_COLOR_R (c), - SWF_COLOR_G (c), SWF_COLOR_B (c)); ++ return g_strdup_printf ("%02X%02X%02X", SWFDEC_COLOR_R (c), ++ SWFDEC_COLOR_G (c), SWFDEC_COLOR_B (c)); +} + +static gboolean +swfedit_rgba_from_string (const char *s, gpointer* result) +{ + guint r, g, b, a; + if (strlen (s) != 8) + return FALSE; + if (!swfedit_parse_hex (s, &a)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &r)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &g)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &b)) + return FALSE; - *result = GUINT_TO_POINTER (SWF_COLOR_COMBINE (r, g, b, a)); ++ *result = GUINT_TO_POINTER (SWFDEC_COLOR_COMBINE (r, g, b, a)); + return TRUE; +} + +static char * +swfedit_rgba_to_string (gconstpointer value) +{ + guint c = GPOINTER_TO_UINT (value); + - return g_strdup_printf ("%02X%02X%02X%02X", SWF_COLOR_R (c), - SWF_COLOR_G (c), SWF_COLOR_B (c), SWF_COLOR_A (c)); ++ return g_strdup_printf ("%02X%02X%02X%02X", SWFDEC_COLOR_R (c), ++ SWFDEC_COLOR_G (c), SWFDEC_COLOR_B (c), SWFDEC_COLOR_A (c)); +} + +struct { + gboolean (* from_string) (const char *s, gpointer *); + char * (* to_string) (gconstpointer value); + void (* free) (gpointer value); +} converters[SWFEDIT_N_TOKENS] = { + { NULL, NULL, g_object_unref }, + { swfedit_binary_from_string, swfedit_binary_to_string, (GDestroyNotify) swfdec_buffer_unref }, + { swfedit_uint8_from_string, swfedit_to_string_unsigned, NULL }, + { swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL }, + { swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL }, + { swfedit_rect_from_string, swfedit_rect_to_string, g_free }, + { swfedit_rgb_from_string, swfedit_rgb_to_string, NULL }, + { swfedit_rgba_from_string, swfedit_rgba_to_string, NULL }, +}; + +/*** GTK_TREE_MODEL ***/ + +#if 0 +# define REPORT g_print ("%s\n", G_STRFUNC) +#else +# define REPORT +#endif +static GtkTreeModelFlags +swfedit_token_get_flags (GtkTreeModel *tree_model) +{ + REPORT; + return 0; +} + +static gint +swfedit_token_get_n_columns (GtkTreeModel *tree_model) +{ + SwfeditToken *token = SWFEDIT_TOKEN (tree_model); + + REPORT; + return token->tokens->len; +} + +static GType +swfedit_token_get_column_type (GtkTreeModel *tree_model, gint index_) +{ + REPORT; + switch (index_) { + case SWFEDIT_COLUMN_NAME: + return G_TYPE_STRING; + case SWFEDIT_COLUMN_VALUE_VISIBLE: + return G_TYPE_BOOLEAN; + case SWFEDIT_COLUMN_VALUE: + return G_TYPE_STRING; + default: + break; + } + g_assert_not_reached (); + return G_TYPE_NONE; +} + +static gboolean +swfedit_token_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) +{ + SwfeditToken *token = SWFEDIT_TOKEN (tree_model); + guint i = gtk_tree_path_get_indices (path)[0]; + SwfeditTokenEntry *entry; + + REPORT; + if (i > token->tokens->len) + return FALSE; + entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); + if (gtk_tree_path_get_depth (path) > 1) { + GtkTreePath *new; + int j; + int *indices; + gboolean ret; + + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + new = gtk_tree_path_new (); + indices = gtk_tree_path_get_indices (path); + for (j = 1; j < gtk_tree_path_get_depth (path); j++) { + gtk_tree_path_append_index (new, indices[j]); + } + ret = swfedit_token_get_iter (GTK_TREE_MODEL (entry->value), iter, new); + gtk_tree_path_free (new); + return ret; + } else { + iter->stamp = 0; /* FIXME */ + iter->user_data = token; + iter->user_data2 = GINT_TO_POINTER (i); + return TRUE; + } +} + +static GtkTreePath * +swfedit_token_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data2), -1); + + REPORT; + while (token->parent) { + guint i; + SwfeditToken *parent = token->parent; + for (i = 0; i < parent->tokens->len; i++) { + SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i); + if (entry->type != SWFEDIT_TOKEN_OBJECT) + continue; + if (entry->value == token) + break; + } + gtk_tree_path_prepend_index (path, i); + token = parent; + } + return path; +} + +static void +swfedit_token_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, + gint column, GValue *value) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); + + REPORT; + switch (column) { + case SWFEDIT_COLUMN_NAME: + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, entry->name); + return; + case SWFEDIT_COLUMN_VALUE_VISIBLE: + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, converters[entry->type].to_string != NULL); + return; + case SWFEDIT_COLUMN_VALUE: + g_value_init (value, G_TYPE_STRING); + if (converters[entry->type].to_string) + g_value_take_string (value, converters[entry->type].to_string (entry->value)); + return; + default: + break; + } + g_assert_not_reached (); +} + +static gboolean +swfedit_token_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + + REPORT; + if ((guint) GPOINTER_TO_INT (iter->user_data2) + 1 >= token->tokens->len) + return FALSE; + + iter->user_data2++; + return TRUE; +} + +static gboolean +swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) +{ + SwfeditToken *token; + SwfeditTokenEntry *entry; + + REPORT; + if (parent) { + token = SWFEDIT_TOKEN (parent->user_data); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2)); + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + token = entry->value; + } else { + token = SWFEDIT_TOKEN (tree_model); + } + if (token->tokens->len == 0) + return FALSE; + iter->stamp = 0; /* FIXME */ + iter->user_data = token; + iter->user_data2 = GINT_TO_POINTER (0); + return TRUE; +} + +static gboolean +swfedit_token_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); + + REPORT; + return entry->type == SWFEDIT_TOKEN_OBJECT && SWFEDIT_TOKEN (entry->value)->tokens->len > 0; +} + +static gint +swfedit_token_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); + + REPORT; + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return 0; + + token = entry->value; + return token->tokens->len; +} + +static gboolean +swfedit_token_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, + GtkTreeIter *parent, gint n) +{ + SwfeditToken *token; + SwfeditTokenEntry *entry; + + REPORT; + if (parent) { + token = SWFEDIT_TOKEN (parent->user_data); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2)); + + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + + token = entry->value; + } else { + token = SWFEDIT_TOKEN (tree_model); + } + if ((guint) n >= token->tokens->len) + return FALSE; + iter->stamp = 0; /* FIXME */ + iter->user_data = token; + iter->user_data2 = GINT_TO_POINTER (n); + return TRUE; +} + +static gboolean +swfedit_token_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) +{ + guint i; + SwfeditToken *token = SWFEDIT_TOKEN (child->user_data); + SwfeditToken *parent = token->parent; + + REPORT; + if (parent == NULL) + return FALSE; + + for (i = 0; i < parent->tokens->len; i++) { + SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i); + if (entry->type != SWFEDIT_TOKEN_OBJECT) + continue; + if (entry->value == token) + break; + } + iter->stamp = 0; /* FIXME */ + iter->user_data = parent; + iter->user_data2 = GINT_TO_POINTER (i); + return TRUE; +} + +static void +swfedit_token_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = swfedit_token_get_flags; + iface->get_n_columns = swfedit_token_get_n_columns; + iface->get_column_type = swfedit_token_get_column_type; + iface->get_iter = swfedit_token_get_iter; + iface->get_path = swfedit_token_get_path; + iface->get_value = swfedit_token_get_value; + iface->iter_next = swfedit_token_iter_next; + iface->iter_children = swfedit_token_iter_children; + iface->iter_has_child = swfedit_token_iter_has_child; + iface->iter_n_children = swfedit_token_iter_n_children; + iface->iter_nth_child = swfedit_token_iter_nth_child; + iface->iter_parent = swfedit_token_iter_parent; +} + +/*** SWFEDIT_TOKEN ***/ + +G_DEFINE_TYPE_WITH_CODE (SwfeditToken, swfedit_token, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, swfedit_token_tree_model_init)) + +static void +swfedit_token_dispose (GObject *object) +{ + SwfeditToken *token = SWFEDIT_TOKEN (object); + guint i; + + for (i = 0; i < token->tokens->len; i++) { + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); + g_free (entry->name); + if (converters[entry->type].free) + converters[entry->type].free (entry->value); + } + g_array_free (token->tokens, TRUE); + + G_OBJECT_CLASS (swfedit_token_parent_class)->dispose (object); +} + +static void +swfedit_token_class_init (SwfeditTokenClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = swfedit_token_dispose; +} + +static void +swfedit_token_init (SwfeditToken *token) +{ + token->tokens = g_array_new (FALSE, FALSE, sizeof (SwfeditTokenEntry)); +} + +SwfeditToken * +swfedit_token_new (void) +{ + SwfeditToken *token; + + token = g_object_new (SWFEDIT_TYPE_TOKEN, NULL); + return token; +} + +void +swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, gpointer value) +{ + SwfeditTokenEntry entry = { NULL, type, value }; + + g_return_if_fail (SWFEDIT_IS_TOKEN (token)); + g_return_if_fail (name != NULL); + g_return_if_fail (type < SWFEDIT_N_TOKENS); + + entry.name = g_strdup (name); + g_array_append_val (token->tokens, entry); +} + +void +swfedit_token_set (SwfeditToken *token, GtkTreeIter *iter, const char *value) +{ + GtkTreeModel *model; + SwfeditTokenEntry *entry; + guint i; + gpointer new; + GtkTreePath *path; + + g_return_if_fail (SWFEDIT_IS_TOKEN (token)); + g_return_if_fail (iter != NULL); + g_return_if_fail (value != NULL); + + model = GTK_TREE_MODEL (token); + token = iter->user_data; + i = GPOINTER_TO_UINT (iter->user_data2); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); + if (converters[entry->type].from_string == NULL) + return; + if (!converters[entry->type].from_string (value, &new)) + return; + if (converters[entry->type].free != NULL) + converters[entry->type].free (entry->value); + entry->value = new; + + path = gtk_tree_model_get_path (model, iter); + gtk_tree_model_row_changed (model, path, iter); + gtk_tree_path_free (path); +} + diff-tree 940ef9614313d253bb9282e26f48968b4af13c85 (from 828ab7af700ce3d9b4e44b90c4f7d804b5d243cc) Author: Benjamin Otte <otte@gnome.org> Date: Fri Feb 2 21:30:02 2007 +0100 missing \n diff --git a/test/swfdec-extract.c b/test/swfdec-extract.c index bea068e..ac79124 100644 --- a/test/swfdec-extract.c +++ b/test/swfdec-extract.c @@ -259,7 +259,7 @@ main (int argc, char *argv[]) if (!export_graphic (SWFDEC_GRAPHIC (character), argv[3])) ret = 1; } else { - g_printerr ("id %ld does not specify an exportable object", id); + g_printerr ("id %ld does not specify an exportable object\n", id); ret = 1; } diff-tree 828ab7af700ce3d9b4e44b90c4f7d804b5d243cc (from parents) Merge: 94e07c556a4e4f471f6700af54f35e55edf79a85 12bf86eb10e873ca735fad310d7ab9e517f6662b Author: Benjamin Otte <otte@gnome.org> Date: Fri Feb 2 19:00:13 2007 +0100 Merge branch 'master' into interpreter diff-tree 94e07c556a4e4f471f6700af54f35e55edf79a85 (from 18aff9069e571bda0bf49290c7ad415597d1d16e) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 16:11:16 2007 +0100 implement WaitForFrame2 videostar.swf works now diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 39b3b8b..c416f64 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -267,6 +267,27 @@ swfdec_action_goto_label (JSContext *cx, return JS_TRUE; } +static int +swfdec_value_to_frame (JSContext *cx, SwfdecMovie *movie, jsval val) +{ + int frame; + + if (JSVAL_IS_STRING (val)) { + const char *name = swfdec_js_to_string (cx, val); + if (name == NULL || + !SWFDEC_IS_SPRITE_MOVIE (movie)) + return -1; + if (strchr (name, ':')) { + SWFDEC_ERROR ("FIXME: handle targets"); + } + frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name); + } else { + /* FIXME: how do we treat undefined etc? */ + frame = swfdec_action_to_number (cx, val); + } + return frame; +} + static JSBool swfdec_action_goto_frame2 (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -274,7 +295,6 @@ swfdec_action_goto_frame2 (JSContext *cx guint bias; gboolean play; jsval val; - int frame; SwfdecMovie *movie; swfdec_bits_init_data (&bits, data, len); @@ -288,24 +308,13 @@ swfdec_action_goto_frame2 (JSContext *cx } val = cx->fp->sp[-1]; cx->fp->sp--; - if (JSVAL_IS_STRING (val)) { - const char *name = swfdec_js_to_string (cx, val); - if (name == NULL) - return JS_FALSE; - if (strchr (name, ':')) { - SWFDEC_ERROR ("FIXME: handle targets"); - } - frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name); - if (frame == -1) - return JS_TRUE; - } else { - /* FIXME: how do we treat undefined etc? */ - frame = swfdec_action_to_number (cx, val); - } - frame += bias; - /* now set it */ movie = swfdec_action_get_target (cx); + /* now set it */ if (movie) { + int frame = swfdec_value_to_frame (cx, movie, val); + if (frame < 0) + return JS_TRUE; + frame += bias; frame = CLAMP (frame, 0, (int) movie->n_frames - 1); swfdec_movie_goto (movie, frame); movie->stopped = !play; @@ -315,6 +324,63 @@ swfdec_action_goto_frame2 (JSContext *cx return JS_TRUE; } +static void +swfdec_script_skip_actions (JSContext *cx, guint jump) +{ + SwfdecScript *script = cx->fp->swf; + guint8 *pc = cx->fp->pc; + guint8 *endpc = script->buffer->data + script->buffer->length; + + /* jump instructions */ + g_assert (script); + do { + if (pc >= endpc) + break; + if (*pc & 0x80) { + if (pc + 2 >= endpc) + break; + pc += 3 + GUINT16_FROM_LE (*((guint16 *) (pc + 1))); + } else { + pc++; + } + } while (jump-- > 0); + cx->fp->pc = pc; +} + +static JSBool +swfdec_action_wait_for_frame2 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval val; + SwfdecMovie *movie; + + if (len != 1) { + SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data"); + return JS_FALSE; + } + val = cx->fp->sp[-1]; + cx->fp->sp--; + movie = swfdec_action_get_target (cx); + if (movie) { + int frame = swfdec_value_to_frame (cx, movie, val); + guint jump = data[2]; + guint loaded; + if (frame < 0) + return JS_TRUE; + if (SWFDEC_IS_ROOT_MOVIE (movie)) { + SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie)->decoder; + loaded = dec->frames_loaded; + g_assert (loaded <= movie->n_frames); + } else { + loaded = movie->n_frames; + } + if (loaded < (guint) frame) + swfdec_script_skip_actions (cx, jump); + } else { + SWFDEC_ERROR ("no movie to WaitForFrame2 on"); + } + return JS_TRUE; +} + static JSBool swfdec_action_wait_for_frame (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -333,32 +399,14 @@ swfdec_action_wait_for_frame (JSContext frame = GUINT16_FROM_LE (*((guint16 *) data)); jump = data[2]; if (SWFDEC_IS_ROOT_MOVIE (movie)) { - SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie->root)->decoder; + SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie)->decoder; loaded = dec->frames_loaded; g_assert (loaded <= movie->n_frames); } else { loaded = movie->n_frames; } - if (loaded < frame) { - SwfdecScript *script = cx->fp->swf; - guint8 *pc = cx->fp->pc; - guint8 *endpc = script->buffer->data + script->buffer->length; - - /* jump instructions */ - g_assert (script); - do { - if (pc >= endpc) - break; - if (*pc & 0x80) { - if (pc + 2 >= endpc) - break; - pc += 3 + GUINT16_FROM_LE (*((guint16 *) (pc + 1))); - } else { - pc++; - } - } while (jump-- > 0); - cx->fp->pc = pc; - } + if (loaded < frame) + swfdec_script_skip_actions (cx, jump); return JS_TRUE; } @@ -1693,6 +1741,16 @@ swfdec_action_print_constant_pool (guint } static char * +swfdec_action_print_wait_for_frame2 (guint action, const guint8 *data, guint len) +{ + if (len != 1) { + SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data"); + return NULL; + } + return g_strdup_printf ("WaitForFrame2 %u", (guint) *data); +} + +static char * swfdec_action_print_goto_frame2 (guint action, const guint8 *data, guint len) { gboolean play, bias; @@ -1868,7 +1926,7 @@ static const SwfdecActionSpec actions[25 [0x8b] = { "SetTarget", swfdec_action_print_set_target, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, [0x8c] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } }, /* version 4 */ - [0x8d] = { "WaitForFrame2", NULL }, + [0x8d] = { "WaitForFrame2", swfdec_action_print_wait_for_frame2, 1, 0, { NULL, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2 } }, /* version 7 */ [0x8e] = { "DefineFunction2", NULL }, [0x8f] = { "Try", NULL }, diff-tree 18aff9069e571bda0bf49290c7ad415597d1d16e (from 81d2a042d8772f2837e088c2fba410ea9b0df082) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 14:38:22 2007 +0100 add another test that resulted from trying various stuff diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am index a5d85ea..d931702 100644 --- a/test/trace/Makefile.am +++ b/test/trace/Makefile.am @@ -76,6 +76,8 @@ EXTRA_DIST = \ name2.swf.trace \ names.swf \ names.swf.trace \ + number.swf \ + number.swf.trace \ object-math-5.swf \ object-math-5.swf.trace \ object-math-6.swf \ diff --git a/test/trace/number.swf b/test/trace/number.swf new file mode 100755 index 0000000..bf729ef Binary files /dev/null and b/test/trace/number.swf differ diff --git a/test/trace/number.swf.trace b/test/trace/number.swf.trace new file mode 100755 index 0000000..de6a5e2 --- /dev/null +++ b/test/trace/number.swf.trace @@ -0,0 +1,9 @@ +Check various things with Number class and prototypes +[type Function] +[type Object] +[type Function] +NaN +42 +1234 +4 +undefined diff-tree 81d2a042d8772f2837e088c2fba410ea9b0df082 (from b6dcac3542c5de3b38b7505ea44be99c95b50de9) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 14:37:13 2007 +0100 various fixes for tests - apparently all objects evaluate to NaN in Flash 7 - handle error case ValueToObject == NULL in CallMethod - walk the whole scope chain in CallFunction when trying to find the function diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index ad08eef..39b3b8b 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -161,7 +161,7 @@ swfdec_action_to_number (JSContext *cx, static JSBool swfdec_value_to_number_7 (JSContext *cx, jsval val, double *d) { - if (JSVAL_IS_NULL (val)) { + if (JSVAL_IS_OBJECT (val)) { *d = *cx->runtime->jsNaN; return JS_TRUE; } else { @@ -550,8 +550,10 @@ swfdec_action_call_function (JSContext * JSStackFrame *fp = cx->fp; const char *s; guint32 n_args; - JSObject *obj; + JSObject *obj, *pobj; + JSProperty *prop; jsval fun; + JSAtom *atom; s = swfdec_js_to_string (cx, fp->sp[-1]); if (s == NULL) @@ -561,7 +563,9 @@ swfdec_action_call_function (JSContext * if (n_args + 2 > (guint) (fp->sp - fp->spbase)) return JS_FALSE; - obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain); + if (!(atom = js_Atomize (cx, s, strlen (s), 0)) || + !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) + return JS_FALSE; if (!JS_GetProperty (cx, obj, s, &fun)) return JS_FALSE; fp->sp[-1] = fun; @@ -589,6 +593,8 @@ swfdec_action_call_method (JSContext *cx if (!JS_ValueToObject (cx, fp->sp[-2], &obj)) return JS_FALSE; + if (obj == NULL) + goto fail; if (s[0] == '\0') { fun = OBJECT_TO_JSVAL (obj); } else { @@ -600,6 +606,11 @@ swfdec_action_call_method (JSContext *cx fp->sp[-2] = OBJECT_TO_JSVAL (obj); swfdec_action_call (cx, n_args, 0); return JS_TRUE; + +fail: + fp->sp -= 2 + n_args; + fp->sp[-1] = JSVAL_VOID; + return JS_TRUE; } static JSBool diff-tree b6dcac3542c5de3b38b7505ea44be99c95b50de9 (from c806924bb1038dd655fef7d2ede3dad8d61dffe6) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 14:30:42 2007 +0100 toString is supposed to output [type Object] for numbers diff --git a/libswfdec/js/jsnum.c b/libswfdec/js/jsnum.c index 1e92a7a..d9063f4 100644 --- a/libswfdec/js/jsnum.c +++ b/libswfdec/js/jsnum.c @@ -249,6 +249,15 @@ IntToString(jsint i, char *buf, size_t b static JSBool num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { + JSString *string; + + string = JS_InternString (cx, "[type Object]"); + if (string == NULL) + return JS_FALSE; + + *rval = STRING_TO_JSVAL (string); + return JS_TRUE; +#if 0 jsval v; jsdouble d; jsint base; @@ -286,6 +295,7 @@ num_toString(JSContext *cx, JSObject *ob return JS_FALSE; *rval = STRING_TO_JSVAL(str); return JS_TRUE; +#endif } static JSBool diff-tree c806924bb1038dd655fef7d2ede3dad8d61dffe6 (from dad7fc07302b9f0b6a13ce837e5ef997d95e75c2) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 13:13:15 2007 +0100 add test for mathematical operations + - * / on objects diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am index 27f0cac..a5d85ea 100644 --- a/test/trace/Makefile.am +++ b/test/trace/Makefile.am @@ -76,6 +76,12 @@ EXTRA_DIST = \ name2.swf.trace \ names.swf \ names.swf.trace \ + object-math-5.swf \ + object-math-5.swf.trace \ + object-math-6.swf \ + object-math-6.swf.trace \ + object-math-7.swf \ + object-math-7.swf.trace \ order.swf \ order.swf.trace \ rotation-5.swf \ diff --git a/test/trace/object-math-5.swf b/test/trace/object-math-5.swf new file mode 100755 index 0000000..7ceac67 Binary files /dev/null and b/test/trace/object-math-5.swf differ diff --git a/test/trace/object-math-5.swf.trace b/test/trace/object-math-5.swf.trace new file mode 100755 index 0000000..03b77fa --- /dev/null +++ b/test/trace/object-math-5.swf.trace @@ -0,0 +1,17 @@ +Check mathematical operations with objects in Flash 5 +2 +2 +2 +2 +2 +-2 +-2 +2 +0 +0 +0 +0 +Infinity +0 +0 +Infinity diff --git a/test/trace/object-math-6.swf b/test/trace/object-math-6.swf new file mode 100755 index 0000000..5f98f7c Binary files /dev/null and b/test/trace/object-math-6.swf differ diff --git a/test/trace/object-math-6.swf.trace b/test/trace/object-math-6.swf.trace new file mode 100755 index 0000000..87fc74d --- /dev/null +++ b/test/trace/object-math-6.swf.trace @@ -0,0 +1,17 @@ +Check mathematical operations with objects in Flash 6 +NaN +NaN +2 +2 +NaN +NaN +-2 +2 +NaN +NaN +0 +0 +Infinity +NaN +0 +Infinity diff --git a/test/trace/object-math-7.swf b/test/trace/object-math-7.swf new file mode 100755 index 0000000..9d9392a Binary files /dev/null and b/test/trace/object-math-7.swf differ diff --git a/test/trace/object-math-7.swf.trace b/test/trace/object-math-7.swf.trace new file mode 100755 index 0000000..751247d --- /dev/null +++ b/test/trace/object-math-7.swf.trace @@ -0,0 +1,17 @@ +Check mathematical operations with objects in Flash 7 +NaN +NaN +NaN +NaN +NaN +NaN +NaN +NaN +NaN +NaN +NaN +NaN +Infinity +NaN +NaN +Infinity diff-tree dad7fc07302b9f0b6a13ce837e5ef997d95e75c2 (from 1677a15cf65bf31fffa806f5e56c5b61e6ae4ffa) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 12:49:46 2007 +0100 fix object to number conversions in Flash 6 Flash <=5 converts all objects to 0 Flash 6 converts non-null objects to NaN and null objects to 0 diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index d79a3d1..ad08eef 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -151,6 +151,8 @@ swfdec_action_to_number (JSContext *cx, if (!JS_ValueToNumber (cx, val, &d)) return 0; return isnan (d) ? 0 : d; + } else if (JSVAL_IS_OBJECT(val) && (((SwfdecScript *) cx->fp->swf)->version >= 6)) { + return JSVAL_IS_NULL (val) ? 0 : *cx->runtime->jsNaN; } else { return 0; } @@ -727,6 +729,8 @@ swfdec_action_binary (JSContext *cx, gui l = l * r; break; case 0x0d: + if (isnan (r)) + r = 0; if (r == 0 && ((SwfdecScript *) cx->fp->swf)->version < 5) { JSString *str = JS_InternString (cx, "#ERROR#"); if (str == NULL) @@ -734,7 +738,7 @@ swfdec_action_binary (JSContext *cx, gui cx->fp->sp[-1] = STRING_TO_JSVAL (str); return JS_TRUE; } else if (((SwfdecScript *) cx->fp->swf)->version >= 7 && - (r == 0 || isnan (r))) { + r == 0) { cx->fp->sp[-1] = DOUBLE_TO_JSVAL (r < 0 ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity); diff-tree 1677a15cf65bf31fffa806f5e56c5b61e6ae4ffa (from f7160413607ea6b82e876fb453c1c4303d3479d5) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 12:29:09 2007 +0100 fix to_number conversions for null in Flash 7 Flash 7 seems to treat null as NaN as opposed to SpiderMonkey, where null is 0. This patch fixes mathematical operations to do this correctly. diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 4c0b163..d79a3d1 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -156,6 +156,17 @@ swfdec_action_to_number (JSContext *cx, } } +static JSBool +swfdec_value_to_number_7 (JSContext *cx, jsval val, double *d) +{ + if (JSVAL_IS_NULL (val)) { + *d = *cx->runtime->jsNaN; + return JS_TRUE; + } else { + return JS_ValueToNumber (cx, val, d); + } +} + /*** ALL THE ACTION IS HERE ***/ static JSBool @@ -700,8 +711,8 @@ swfdec_action_binary (JSContext *cx, gui l = swfdec_action_to_number (cx, lval); r = swfdec_action_to_number (cx, rval); } else { - if (!JS_ValueToNumber(cx, lval, &l) || - !JS_ValueToNumber(cx, rval, &r)) + if (!swfdec_value_to_number_7 (cx, lval, &l) || + !swfdec_value_to_number_7 (cx, rval, &r)) return JS_FALSE; } cx->fp->sp--; @@ -722,9 +733,8 @@ swfdec_action_binary (JSContext *cx, gui return JS_FALSE; cx->fp->sp[-1] = STRING_TO_JSVAL (str); return JS_TRUE; - } - if (((SwfdecScript *) cx->fp->swf)->version >= 7 && - JSVAL_IS_VOID (rval)) { + } else if (((SwfdecScript *) cx->fp->swf)->version >= 7 && + (r == 0 || isnan (r))) { cx->fp->sp[-1] = DOUBLE_TO_JSVAL (r < 0 ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity); @@ -790,14 +800,6 @@ swfdec_action_add2_7 (JSContext *cx, gui rval = cx->fp->sp[-1]; lval = cx->fp->sp[-2]; - if (!JSVAL_IS_PRIMITIVE (rval)) { - if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT (rval), 0 , &rval)) - return JS_FALSE; - } - if (!JSVAL_IS_PRIMITIVE (lval)) { - if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT (lval), 0 , &lval)) - return JS_FALSE; - } if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) { JSString *str, *str2; if (cond) { @@ -816,8 +818,8 @@ swfdec_action_add2_7 (JSContext *cx, gui cx->fp->sp[-1] = STRING_TO_JSVAL (str); } else { double d, d2; - if (!JS_ValueToNumber(cx, lval, &d) || - !JS_ValueToNumber(cx, rval, &d2)) + if (!swfdec_value_to_number_7 (cx, lval, &d) || + !swfdec_value_to_number_7 (cx, rval, &d2)) return JS_FALSE; d += d2; cx->fp->sp--; diff-tree f7160413607ea6b82e876fb453c1c4303d3479d5 (from ecffa559b35162ca6e2cb8bc20fe9f2ee7c43ba6) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 11:35:42 2007 +0100 allow calling functions on numbers and strings by converting them to proper objects diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 85e6f7c..4c0b163 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -574,9 +574,8 @@ swfdec_action_call_method (JSContext *cx if (n_args + 3 > (guint) (fp->sp - fp->spbase)) return JS_FALSE; - if (!JSVAL_IS_OBJECT (fp->sp[-2]) || JSVAL_IS_NULL (fp->sp[-2])) - goto fail; - obj = JSVAL_TO_OBJECT (fp->sp[-2]); + if (!JS_ValueToObject (cx, fp->sp[-2], &obj)) + return JS_FALSE; if (s[0] == '\0') { fun = OBJECT_TO_JSVAL (obj); } else { @@ -588,11 +587,6 @@ swfdec_action_call_method (JSContext *cx fp->sp[-2] = OBJECT_TO_JSVAL (obj); swfdec_action_call (cx, n_args, 0); return JS_TRUE; - -fail: - fp->sp -= 2 + n_args; - fp->sp[-1] = JSVAL_VOID; - return JS_TRUE; } static JSBool diff-tree ecffa559b35162ca6e2cb8bc20fe9f2ee7c43ba6 (from 320efb52606b8b376880b9c3bc222a1f9810896a) Author: Benjamin Otte <otte@gnome.org> Date: Thu Feb 1 11:35:08 2007 +0100 add a column for the type of the object on the stack diff --git a/player/swfdec_debug_stack.c b/player/swfdec_debug_stack.c index 2eef4ed..5b25626 100644 --- a/player/swfdec_debug_stack.c +++ b/player/swfdec_debug_stack.c @@ -30,17 +30,37 @@ G_DEFINE_TYPE (SwfdecDebugStack, swfdec_ enum { COLUMN_LINE, + COLUMN_TYPE, COLUMN_CONTENT, N_COLUMNS }; +static const char * +swfdec_get_jsval_type (JSContext *cx, jsval val) +{ + if (JSVAL_IS_VOID (val)) + return "undefined"; + if (JSVAL_IS_NULL (val)) + return "null"; + if (JSVAL_IS_INT (val)) + return "Integer"; + if (JSVAL_IS_DOUBLE (val)) + return "Double"; + if (JSVAL_IS_BOOLEAN (val)) + return "Boolean"; + if (JSVAL_IS_STRING (val)) + return "String"; + g_assert (JSVAL_IS_OBJECT (val)); + return "Object"; +} + static void swfdec_debug_stack_set_model (SwfdecDebugStack *debug) { JSStackFrame *frame = NULL; guint i, min, max; GtkListStore *store = gtk_list_store_new (N_COLUMNS, G_TYPE_UINT, - G_TYPE_STRING); + G_TYPE_STRING, G_TYPE_STRING); GtkTreeIter iter; JS_FrameIterator (debug->manager->player->jscx, &frame); @@ -49,7 +69,9 @@ swfdec_debug_stack_set_model (SwfdecDebu for (i = min; i <= max; i++) { const char *s = swfdec_js_to_string (debug->manager->player->jscx, frame->sp[-i]); gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, COLUMN_LINE, i, COLUMN_CONTENT, s, -1); + gtk_list_store_set (store, &iter, COLUMN_LINE, i, + COLUMN_TYPE, swfdec_get_jsval_type (debug->manager->player->jscx, frame->sp[-i]), + COLUMN_CONTENT, s, -1); } gtk_tree_view_set_model (GTK_TREE_VIEW (debug), GTK_TREE_MODEL (store)); @@ -119,6 +141,13 @@ swfdec_debug_stack_add_columns (GtkTreeV gtk_tree_view_append_column (treeview, column); renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Type", renderer, + "text", COLUMN_TYPE, NULL); + gtk_tree_view_column_set_sort_column_id (column, COLUMN_TYPE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (treeview, column); + + renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Content", renderer, "text", COLUMN_CONTENT, NULL); gtk_tree_view_column_set_sort_column_id (column, COLUMN_CONTENT); diff-tree 320efb52606b8b376880b9c3bc222a1f9810896a (from ae64862c94f18618313c90c28b4071d84693b7b5) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 23:33:40 2007 +0100 implement ConstantPool inheritance for DefineFunction diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 46ba618..85e6f7c 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -97,6 +97,26 @@ swfdec_constant_pool_free (SwfdecConstan g_ptr_array_free (pool, TRUE); } +/* FIXME: this is a bit hacky */ +static SwfdecBuffer * +swfdec_constant_pool_get_area (SwfdecScript *script, SwfdecConstantPool *pool) +{ + guint8 *start; + SwfdecBuffer *buffer; + guint len; + + if (pool->len == 0) + return NULL; + start = (guint8 *) g_ptr_array_index (pool, 0) - 5; + buffer = script->buffer; + g_assert (start >= buffer->data); + g_assert (start + 3 < buffer->data + buffer->length); + g_assert (*start == 0x88); + len = 3 + (start[1] | start[2] << 8); + g_assert (start + len < buffer->data + buffer->length); + return swfdec_buffer_new_subbuffer (buffer, start - buffer->data, len); +} + /*** SUPPORT FUNCTIONS ***/ static SwfdecMovie * @@ -1334,6 +1354,10 @@ swfdec_action_define_function (JSContext &bits, *function_name ? function_name : "<lambda>", ((SwfdecScript *) cx->fp->swf)->version); swfdec_buffer_unref (buffer); + if (cx->fp->constant_pool) { + script->constant_pool = swfdec_constant_pool_get_area (cx->fp->swf, + cx->fp->constant_pool); + } } if (script == NULL) { SWFDEC_ERROR ("failed to create script"); @@ -1638,6 +1662,7 @@ swfdec_action_print_push (guint action, return g_string_free (string, FALSE); } +/* NB: constant pool actions are special in that they are called at init time */ static char * swfdec_action_print_constant_pool (guint action, const guint8 *data, guint len) { @@ -2010,6 +2035,8 @@ swfdec_script_unref (SwfdecScript *scrip return; swfdec_buffer_unref (script->buffer); + if (script->constant_pool) + swfdec_buffer_unref (script->constant_pool); g_free (script->name); g_free (script); } @@ -2068,6 +2095,16 @@ swfdec_script_interpret (SwfdecScript *s ok = JS_FALSE; goto out; } + /* initialize the constant pool */ + if (script->constant_pool) { + spec = actions + 0x88; + ok = spec->exec[version] (cx, 0x88, script->constant_pool->data + 3, + script->constant_pool->length - 3); + if (!ok) { + SWFDEC_WARNING ("Constant pool initialization failed"); + goto out; + } + } while (TRUE) { /* check pc */ diff --git a/libswfdec/swfdec_script.h b/libswfdec/swfdec_script.h index 1cea4a7..e202aa0 100644 --- a/libswfdec/swfdec_script.h +++ b/libswfdec/swfdec_script.h @@ -39,6 +39,8 @@ struct _SwfdecScript { char * name; /* name identifying this script */ unsigned int version; /* version of the script */ gpointer debugger; /* debugger owning us or NULL */ + /* needed by functions */ + SwfdecBuffer * constant_pool; /* constant pool action */ }; SwfdecScript * swfdec_script_new (SwfdecBits * bits, diff-tree ae64862c94f18618313c90c28b4071d84693b7b5 (from 71b090ccdeedb1e96b2f8590844844139b00bd85) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 21:35:50 2007 +0100 implement BitAnd, BitOr, BitXor, DefineLocal, DefineLocal2 and Return diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 9b3a328..46ba618 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1359,6 +1359,35 @@ swfdec_action_define_function (JSContext } static JSBool +swfdec_action_bitwise (JSContext *cx, guint action, const guint8 *data, guint len) +{ + guint32 a, b; + double d; + + if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &a) || + !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &b)) + return JS_FALSE; + + switch (action) { + case 0x60: + d = (int) (a & b); + break; + case 0x61: + d = (int) (a | b); + break; + case 0x62: + d = (int) (a ^ b); + break; + default: + g_assert_not_reached (); + return JS_FALSE; + } + + cx->fp->sp--; + return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); +} + +static JSBool swfdec_action_shift (JSContext *cx, guint action, const guint8 *data, guint len) { guint32 amount, value; @@ -1414,6 +1443,54 @@ swfdec_action_target_path (JSContext *cx return JS_TRUE; } +static JSBool +swfdec_action_define_local (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *name; + + if (cx->fp->callobj == NULL) { + SWFDEC_ERROR ("FIXME: no local scope"); + return JS_FALSE; + } + name = swfdec_js_to_string (cx, cx->fp->sp[-2]); + if (name == NULL) + return JS_FALSE; + if (!JS_SetProperty (cx, cx->fp->callobj, name, &cx->fp->sp[-1])) + return JS_FALSE; + cx->fp->sp -= 2; + return JS_TRUE; +} + +static JSBool +swfdec_action_define_local2 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *name; + jsval val = JSVAL_VOID; + + if (cx->fp->callobj == NULL) { + SWFDEC_ERROR ("FIXME: no local scope"); + return JS_FALSE; + } + name = swfdec_js_to_string (cx, cx->fp->sp[-1]); + if (name == NULL) + return JS_FALSE; + if (!JS_SetProperty (cx, cx->fp->callobj, name, &val)) + return JS_FALSE; + cx->fp->sp--; + return JS_TRUE; +} + +static JSBool +swfdec_action_return (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecScript *script = cx->fp->swf; + + cx->fp->rval = cx->fp->sp[-1]; + cx->fp->pc = script->buffer->data + script->buffer->length; + cx->fp->sp--; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1703,12 +1780,12 @@ static const SwfdecActionSpec actions[25 /* version 5 */ [0x3a] = { "Delete", NULL }, [0x3b] = { "Delete2", NULL }, - [0x3c] = { "DefineLocal", NULL }, //, 2, 0, { NULL, NULL, swfdec_action_define_local, swfdec_action_define_local, swfdec_action_define_local } }, + [0x3c] = { "DefineLocal", NULL, 2, 0, { NULL, NULL, swfdec_action_define_local, swfdec_action_define_local, swfdec_action_define_local } }, [0x3d] = { "CallFunction", NULL, -1, 1, { NULL, NULL, swfdec_action_call_function, swfdec_action_call_function, swfdec_action_call_function } }, - [0x3e] = { "Return", NULL }, + [0x3e] = { "Return", NULL, 1, 0, { NULL, NULL, swfdec_action_return, swfdec_action_return, swfdec_action_return } }, [0x3f] = { "Modulo", NULL }, [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } }, - [0x41] = { "DefineLocal2", NULL }, + [0x41] = { "DefineLocal2", NULL, 1, 0, { NULL, NULL, swfdec_action_define_local2, swfdec_action_define_local2, swfdec_action_define_local2 } }, [0x42] = { "InitArray", NULL }, [0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } }, [0x44] = { "Typeof", NULL }, @@ -1731,9 +1808,9 @@ static const SwfdecActionSpec actions[25 [0x54] = { "InstanceOf", NULL }, [0x55] = { "Enumerate2", NULL }, /* version 5 */ - [0x60] = { "BitAnd", NULL }, - [0x61] = { "BitOr", NULL }, - [0x62] = { "BitXor", NULL }, + [0x60] = { "BitAnd", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } }, + [0x61] = { "BitOr", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } }, + [0x62] = { "BitXor", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } }, [0x63] = { "BitLShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, [0x64] = { "BitRShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, [0x65] = { "BitURShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, @@ -1994,8 +2071,11 @@ swfdec_script_interpret (SwfdecScript *s while (TRUE) { /* check pc */ - if (pc == endpc) /* needed for scripts created via DefineFunction */ + if (pc == endpc) { + /* scripts created via DefineFunction or the Return action use this way out */ + *rval = fp->rval; break; + } if (pc < startpc || pc >= endpc) { SWFDEC_ERROR ("pc %p not in valid range [%p, %p) anymore", pc, startpc, endpc); goto internal_error; diff-tree 71b090ccdeedb1e96b2f8590844844139b00bd85 (from fa4f57c436b5f6232efacfa2b4ac94d14af1f409) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 19:59:15 2007 +0100 initialize the constant pool as empty diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c index ce8d014..910087a 100644 --- a/libswfdec/js/jsinterp.c +++ b/libswfdec/js/jsinterp.c @@ -847,6 +847,7 @@ have_fun: frame.sharpArray = NULL; frame.dormantNext = NULL; frame.objAtomMap = NULL; + frame.constant_pool = NULL; /* Compute the 'this' parameter and store it in frame as frame.thisp. */ ok = ComputeThis(cx, thisp, &frame); @@ -1140,6 +1141,7 @@ js_Execute(JSContext *cx, JSObject *chai frame.flags = special; frame.dormantNext = NULL; frame.objAtomMap = NULL; + frame.constant_pool = NULL; /* * Here we wrap the call to js_Interpret with code to (conditionally) diff-tree fa4f57c436b5f6232efacfa2b4ac94d14af1f409 (from 9335e136a9a1f2f3dbbbda7a7b156b55d94e7c4c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 17:28:14 2007 +0100 implement Equals This is the last action that the compiler had implemented and this branch hadn't diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 7c24b10..9b3a328 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1019,7 +1019,7 @@ swfdec_action_random_number (JSContext * } static JSBool -swfdec_action_less (JSContext *cx, guint action, const guint8 *data, guint len) +swfdec_action_old_compare (JSContext *cx, guint action, const guint8 *data, guint len) { jsval rval, lval; double l, r; @@ -1029,7 +1029,17 @@ swfdec_action_less (JSContext *cx, guint lval = cx->fp->sp[-2]; l = swfdec_action_to_number (cx, lval); r = swfdec_action_to_number (cx, rval); - cond = l < r; + switch (action) { + case 0x0e: + cond = l == r; + break; + case 0x0f: + cond = l < r; + break; + default: + g_assert_not_reached (); + return JS_FALSE; + } cx->fp->sp--; if (((SwfdecScript *) cx->fp->swf)->version < 5) { cx->fp->sp[-1] = INT_TO_JSVAL (cond ? 1 : 0); @@ -1655,8 +1665,8 @@ static const SwfdecActionSpec actions[25 [0x0b] = { "Subtract", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, [0x0c] = { "Multiply", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, [0x0d] = { "Divide", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, - [0x0e] = { "Equals", NULL }, - [0x0f] = { "Less", NULL, 2, 1, { NULL, swfdec_action_less, swfdec_action_less, swfdec_action_less, swfdec_action_less } }, + [0x0e] = { "Equals", NULL, 2, 1, { NULL, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare } }, + [0x0f] = { "Less", NULL, 2, 1, { NULL, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare } }, [0x10] = { "And", NULL }, [0x11] = { "Or", NULL }, [0x12] = { "Not", NULL, 1, 1, { NULL, swfdec_action_not_4, swfdec_action_not_5, swfdec_action_not_5, swfdec_action_not_5 } }, @@ -1705,7 +1715,7 @@ static const SwfdecActionSpec actions[25 [0x45] = { "TargetPath", NULL, 1, 1, { NULL, NULL, swfdec_action_target_path, swfdec_action_target_path, swfdec_action_target_path } }, [0x46] = { "Enumerate", NULL }, [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } }, - [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, + [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, [0x49] = { "Equals2", NULL, 2, 1, { NULL, NULL, swfdec_action_equals2, swfdec_action_equals2, swfdec_action_equals2 } }, [0x4a] = { "ToNumber", NULL }, [0x4b] = { "ToString", NULL }, diff-tree 9335e136a9a1f2f3dbbbda7a7b156b55d94e7c4c (from 90bd9323aab5388329dfac37a165bd421818875c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:28:09 2007 +0100 handle colors not referring to movies This also fixes the color-new test diff --git a/libswfdec/swfdec_js_color.c b/libswfdec/swfdec_js_color.c index ade8d6a..095abd7 100644 --- a/libswfdec/swfdec_js_color.c +++ b/libswfdec/swfdec_js_color.c @@ -32,7 +32,8 @@ swfdec_js_color_get_rgb (JSContext *cx, int result; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); + if (!movie) + return JS_TRUE; result = (movie->color_transform.rb << 16) | ((movie->color_transform.gb % 256) << 8) | (movie->color_transform.bb % 256); @@ -55,7 +56,8 @@ swfdec_js_color_get_transform (JSContext JSObject *ret; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); + if (!movie) + return JS_TRUE; ret = JS_NewObject (cx, NULL, NULL, NULL); if (ret == NULL) return JS_TRUE; @@ -78,7 +80,8 @@ swfdec_js_color_set_rgb (JSContext *cx, unsigned int color; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); + if (!movie) + return JS_TRUE; if (!JS_ValueToECMAUint32 (cx, argv[0], &color)) return JS_TRUE; @@ -117,8 +120,9 @@ swfdec_js_color_set_transform (JSContext JSObject *parse; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); - if (!JSVAL_IS_OBJECT (argv[0])) + if (!movie) + return JS_TRUE; + if (!movie) return JS_TRUE; parse = JSVAL_TO_OBJECT (argv[0]); parse_property (cx, parse, "ra", &movie->color_transform.ra, TRUE); @@ -161,7 +165,6 @@ swfdec_js_color_finalize (JSContext *cx, SwfdecMovie *movie; movie = JS_GetPrivate (cx, obj); - /* since we also finalize the class, not everyone has a private object */ if (movie) { g_object_unref (movie); } @@ -179,14 +182,16 @@ swfdec_js_color_new (JSContext *cx, JSOb { SwfdecMovie *movie; - movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE); - if (movie == NULL) { - SWFDEC_INFO ("attempted to construct a color without a movie"); - return JS_TRUE; + if (argc > 0) { + movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE); + } else { + movie = NULL; + } + if (movie != NULL) { + if (!JS_SetPrivate (cx, obj, movie)) + return JS_FALSE; + g_object_ref (movie); } - if (!JS_SetPrivate (cx, obj, movie)) - return JS_TRUE; - g_object_ref (movie); *rval = OBJECT_TO_JSVAL (obj); return JS_TRUE; } @@ -195,7 +200,7 @@ void swfdec_js_add_color (SwfdecPlayer *player) { JS_InitClass (player->jscx, player->jsobj, NULL, - &color_class, swfdec_js_color_new, 1, NULL, color_methods, + &color_class, swfdec_js_color_new, 0, NULL, color_methods, NULL, NULL); } diff-tree 90bd9323aab5388329dfac37a165bd421818875c (from 97a972c232892d919de3045f69e6fc3fac4b8ad3) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:27:20 2007 +0100 add print function for SetTarget diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 9921af8..7c24b10 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1407,6 +1407,15 @@ swfdec_action_target_path (JSContext *cx /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_set_target (guint action, const guint8 *data, guint len) +{ + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("SetTarget action does not specify a string"); + return JS_FALSE; + } + return g_strconcat ("SetTarget ", data, NULL); +} +static char * swfdec_action_print_define_function (guint action, const guint8 *data, guint len) { SwfdecBits bits; @@ -1733,7 +1742,7 @@ static const SwfdecActionSpec actions[25 [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } }, /* version 3 */ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, - [0x8b] = { "SetTarget", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, + [0x8b] = { "SetTarget", swfdec_action_print_set_target, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, [0x8c] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } }, /* version 4 */ [0x8d] = { "WaitForFrame2", NULL }, diff-tree 97a972c232892d919de3045f69e6fc3fac4b8ad3 (from 4b0e92902dcfd08e55f34d6d56aecb10efac9314) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:26:51 2007 +0100 make eval (obj, "") return obj and not undefined diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 829c1ad..4c14100 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -343,7 +343,7 @@ static gboolean swfdec_js_eval_internal (JSContext *cx, JSObject *obj, const char *str, jsval *val, gboolean set) { - jsval cur = JSVAL_NULL; + jsval cur; char *work = NULL; SWFDEC_LOG ("eval called with \"%s\" on %p", str, obj); @@ -358,8 +358,8 @@ swfdec_js_eval_internal (JSContext *cx, if (cx->fp == NULL) goto out; obj = cx->fp->thisp; - cur = OBJECT_TO_JSVAL (obj); } + cur = OBJECT_TO_JSVAL (obj); while (str != NULL && *str != '\0') { char *dot = strchr (str, '.'); if (!JSVAL_IS_OBJECT (cur)) diff-tree 4b0e92902dcfd08e55f34d6d56aecb10efac9314 (from 29607ca556843663468425ffad907e69839a0d8f) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:26:04 2007 +0100 add test for Color constructor diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am index 443cba2..27f0cac 100644 --- a/test/trace/Makefile.am +++ b/test/trace/Makefile.am @@ -16,6 +16,8 @@ EXTRA_DIST = \ children.swf.trace \ color-getters.swf \ color-getters.swf.trace \ + color-new.swf \ + color-new.swf.trace \ color-setRGB.swf \ color-setRGB.swf.trace \ color-setTransform-alpha.swf \ diff --git a/test/trace/color-new.swf b/test/trace/color-new.swf new file mode 100755 index 0000000..e9f9727 Binary files /dev/null and b/test/trace/color-new.swf differ diff --git a/test/trace/color-new.swf.trace b/test/trace/color-new.swf.trace new file mode 100755 index 0000000..eb220d7 --- /dev/null +++ b/test/trace/color-new.swf.trace @@ -0,0 +1,10 @@ +test behaviour of Color when created without a movie +[object Object] +undefined +undefined +[object Object] +undefined +undefined +[object Object] +undefined +undefined diff-tree 29607ca556843663468425ffad907e69839a0d8f (from 62447e55d8fb4b74154694683d47070cd49e9868) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 14:50:27 2007 +0100 implement NextFrame, PreviousFrame, ToInteger, TargetPath, GotoLabel, GotoFrame2 Those are the actions needed by South Park studio diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index b172ec6..9921af8 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -35,6 +35,8 @@ #include "swfdec_movie.h" #include "swfdec_player_internal.h" #include "swfdec_root_movie.h" +#include "swfdec_sprite.h" +#include "swfdec_sprite_movie.h" #include "js/jsfun.h" #include "js/jsscope.h" @@ -115,6 +117,25 @@ swfdec_action_push_string (JSContext *cx return JS_TRUE; } +static double +swfdec_action_to_number (JSContext *cx, jsval val) +{ + if (JSVAL_IS_INT (val)) { + return JSVAL_TO_INT (val); + } else if (JSVAL_IS_DOUBLE (val)) { + return *JSVAL_TO_DOUBLE (val); + } else if (JSVAL_IS_BOOLEAN (val)) { + return JSVAL_TO_BOOLEAN (val); + } else if (JSVAL_IS_STRING (val)) { + double d; + if (!JS_ValueToNumber (cx, val, &d)) + return 0; + return isnan (d) ? 0 : d; + } else { + return 0; + } +} + /*** ALL THE ACTION IS HERE ***/ static JSBool @@ -140,6 +161,38 @@ swfdec_action_play (JSContext *cx, guint } static JSBool +swfdec_action_next_frame (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + if (movie) { + if (movie->frame + 1 < movie->n_frames) { + swfdec_movie_goto (movie, movie->frame + 1); + } else { + SWFDEC_INFO ("can't execute nextFrame, already at last frame"); + } + } else { + SWFDEC_ERROR ("no movie to nextFrame on"); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_previous_frame (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + if (movie) { + if (movie->frame > 0) { + swfdec_movie_goto (movie, movie->frame - 1); + } else { + SWFDEC_INFO ("can't execute previousFrame, already at first frame"); + } + } else { + SWFDEC_ERROR ("no movie to previousFrame on"); + } + return JS_TRUE; +} + +static JSBool swfdec_action_goto_frame (JSContext *cx, guint action, const guint8 *data, guint len) { SwfdecMovie *movie = swfdec_action_get_target (cx); @@ -160,6 +213,76 @@ swfdec_action_goto_frame (JSContext *cx, } static JSBool +swfdec_action_goto_label (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("GotoLabel action does not specify a string"); + return JS_FALSE; + } + + if (SWFDEC_IS_SPRITE_MOVIE (movie)) { + int frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, (const char *) data); + if (frame == -1) + return JS_TRUE; + swfdec_movie_goto (movie, frame); + movie->stopped = TRUE; + } else { + SWFDEC_ERROR ("no movie to goto on"); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_goto_frame2 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecBits bits; + guint bias; + gboolean play; + jsval val; + int frame; + SwfdecMovie *movie; + + swfdec_bits_init_data (&bits, data, len); + if (swfdec_bits_getbits (&bits, 6)) { + SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0"); + } + bias = swfdec_bits_getbit (&bits); + play = swfdec_bits_getbit (&bits); + if (bias) { + bias = swfdec_bits_get_u16 (&bits); + } + val = cx->fp->sp[-1]; + cx->fp->sp--; + if (JSVAL_IS_STRING (val)) { + const char *name = swfdec_js_to_string (cx, val); + if (name == NULL) + return JS_FALSE; + if (strchr (name, ':')) { + SWFDEC_ERROR ("FIXME: handle targets"); + } + frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name); + if (frame == -1) + return JS_TRUE; + } else { + /* FIXME: how do we treat undefined etc? */ + frame = swfdec_action_to_number (cx, val); + } + frame += bias; + /* now set it */ + movie = swfdec_action_get_target (cx); + if (movie) { + frame = CLAMP (frame, 0, (int) movie->n_frames - 1); + swfdec_movie_goto (movie, frame); + movie->stopped = !play; + } else { + SWFDEC_ERROR ("no movie to GotoFrame2 on"); + } + return JS_TRUE; +} + +static JSBool swfdec_action_wait_for_frame (JSContext *cx, guint action, const guint8 *data, guint len) { SwfdecMovie *movie = swfdec_action_get_target (cx); @@ -551,25 +674,6 @@ out: return JS_TRUE; } -static double -swfdec_action_to_number (JSContext *cx, jsval val) -{ - if (JSVAL_IS_INT (val)) { - return JSVAL_TO_INT (val); - } else if (JSVAL_IS_DOUBLE (val)) { - return *JSVAL_TO_DOUBLE (val); - } else if (JSVAL_IS_BOOLEAN (val)) { - return JSVAL_TO_BOOLEAN (val); - } else if (JSVAL_IS_STRING (val)) { - double d; - if (!JS_ValueToNumber (cx, val, &d)) - return 0; - return isnan (d) ? 0 : d; - } else { - return 0; - } -} - static JSBool swfdec_action_binary (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -1274,6 +1378,32 @@ swfdec_action_shift (JSContext *cx, guin return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); } +static JSBool +swfdec_action_to_integer (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + + return JS_NewNumberValue (cx, (int) d, &cx->fp->sp[-1]); +} + +static JSBool +swfdec_action_target_path (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_scriptable_from_jsval (cx, cx->fp->sp[-1], SWFDEC_TYPE_MOVIE); + + if (movie == NULL) { + cx->fp->sp[-1] = JSVAL_VOID; + } else { + char *s = swfdec_movie_get_path (movie); + JSString *string = JS_NewStringCopyZ (cx, s); + g_free (s); + if (string == NULL) + return JS_FALSE; + cx->fp->sp[-1] = STRING_TO_JSVAL (string); + } + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1431,6 +1561,26 @@ swfdec_action_print_constant_pool (guint } static char * +swfdec_action_print_goto_frame2 (guint action, const guint8 *data, guint len) +{ + gboolean play, bias; + SwfdecBits bits; + + swfdec_bits_init_data (&bits, data, len); + if (swfdec_bits_getbits (&bits, 6)) { + SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0"); + } + bias = swfdec_bits_getbit (&bits); + play = swfdec_bits_getbit (&bits); + if (bias) { + return g_strdup_printf ("GotoFrame2 %s +%u", play ? "play" : "stop", + swfdec_bits_get_u16 (&bits)); + } else { + return g_strdup_printf ("GotoFrame2 %s", play ? "play" : "stop"); + } +} + +static char * swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len) { guint frame; @@ -1443,6 +1593,17 @@ swfdec_action_print_goto_frame (guint ac } static char * +swfdec_action_print_goto_label (guint action, const guint8 *data, guint len) +{ + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("GotoLabel action does not specify a string"); + return NULL; + } + + return g_strdup_printf ("GotoLabel %s", data); +} + +static char * swfdec_action_print_wait_for_frame (guint action, const guint8 *data, guint len) { guint frame, jump; @@ -1474,8 +1635,8 @@ typedef struct { static const SwfdecActionSpec actions[256] = { /* version 3 */ - [0x04] = { "NextFrame", NULL }, - [0x05] = { "PreviousFrame", NULL }, + [0x04] = { "NextFrame", NULL, 0, 0, { swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame } }, + [0x05] = { "PreviousFrame", NULL, 0, 0, { swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame } }, [0x06] = { "Play", NULL, 0, 0, { swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play } }, [0x07] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } }, [0x08] = { "ToggleQuality", NULL }, @@ -1494,10 +1655,10 @@ static const SwfdecActionSpec actions[25 [0x14] = { "StringLength", NULL }, [0x15] = { "StringExtract", NULL }, [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } }, - [0x18] = { "ToInteger", NULL }, + [0x18] = { "ToInteger", NULL, 1, 1, { NULL, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer } }, [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } }, - [0x20] = { "SetTarget22", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } }, + [0x20] = { "SetTarget2", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } }, [0x21] = { "StringAdd", NULL, 2, 1, { NULL, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add } }, [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } }, [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } }, @@ -1532,7 +1693,7 @@ static const SwfdecActionSpec actions[25 [0x42] = { "InitArray", NULL }, [0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } }, [0x44] = { "Typeof", NULL }, - [0x45] = { "TargetPath", NULL }, + [0x45] = { "TargetPath", NULL, 1, 1, { NULL, NULL, swfdec_action_target_path, swfdec_action_target_path, swfdec_action_target_path } }, [0x46] = { "Enumerate", NULL }, [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } }, [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, @@ -1573,7 +1734,7 @@ static const SwfdecActionSpec actions[25 /* version 3 */ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, [0x8b] = { "SetTarget", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, - [0x8c] = { "GotoLabel", NULL }, + [0x8c] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } }, /* version 4 */ [0x8d] = { "WaitForFrame2", NULL }, /* version 7 */ @@ -1590,7 +1751,7 @@ static const SwfdecActionSpec actions[25 /* version 4 */ [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } }, [0x9e] = { "Call", NULL }, - [0x9f] = { "GotoFrame2", NULL } + [0x9f] = { "GotoFrame2", swfdec_action_print_goto_frame2, 1, 0, { NULL, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2 } } }; char * diff-tree 62447e55d8fb4b74154694683d47070cd49e9868 (from 75e9e227691415642b037d6be0ff7c2ccc90772c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 14:48:56 2007 +0100 add swfdec_movie_get_path The function returns the "path" as used in ActionScript diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c index 70ddece..d33ba94 100644 --- a/libswfdec/swfdec_js_movie.c +++ b/libswfdec/swfdec_js_movie.c @@ -464,36 +464,19 @@ swfdec_js_getURL (JSContext *cx, JSObjec return JS_TRUE; } -static GString * -get_name (SwfdecMovie *movie) -{ - GString *s; - - if (movie->parent) { - s = get_name (movie->parent); - g_string_append_c (s, '.'); - g_string_append (s, movie->name); - } else { - /* the name can be changed */ - s = g_string_new ("_level"); - g_string_append_printf (s, "%u", movie->depth + 16384); - } - return s; -} - static JSBool swfdec_js_movie_to_string (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - GString *s; + char *s; JSString *string; SwfdecMovie *movie; movie = JS_GetPrivate (cx, obj); g_assert (movie); - s = get_name (movie); - string = JS_NewStringCopyZ (cx, s->str); - g_string_free (s, TRUE); + s = swfdec_movie_get_path (movie); + string = JS_NewStringCopyZ (cx, s); + g_free (s); if (string == NULL) return JS_FALSE; *rval = STRING_TO_JSVAL (string); diff --git a/libswfdec/swfdec_movie.c b/libswfdec/swfdec_movie.c index a851cd2..3ab9c88 100644 --- a/libswfdec/swfdec_movie.c +++ b/libswfdec/swfdec_movie.c @@ -787,6 +787,30 @@ swfdec_movie_goto (SwfdecMovie *movie, g klass->goto_frame (movie, frame); } +char * +swfdec_movie_get_path (SwfdecMovie *movie) +{ + GString *s; + + g_return_val_if_fail (SWFDEC_IS_MOVIE (movie), NULL); + + s = g_string_new (""); + do { + if (movie->parent) { + g_string_prepend (s, movie->name); + g_string_prepend_c (s, '.'); + } else { + char *ret = g_strdup_printf ("_level%u%s", + movie->depth + 16384, s->str); + g_string_free (s, TRUE); + return ret; + } + movie = movie->parent; + } while (TRUE); + g_assert_not_reached (); + return NULL; +} + int swfdec_movie_compare_depths (gconstpointer a, gconstpointer b) { diff --git a/libswfdec/swfdec_movie.h b/libswfdec/swfdec_movie.h index 61f495c..0351b54 100644 --- a/libswfdec/swfdec_movie.h +++ b/libswfdec/swfdec_movie.h @@ -177,6 +177,7 @@ void swfdec_movie_send_mouse_change (Sw SwfdecMovie * swfdec_movie_get_movie_at (SwfdecMovie * movie, double x, double y); +char * swfdec_movie_get_path (SwfdecMovie * movie); void swfdec_movie_render (SwfdecMovie * movie, cairo_t * cr, const SwfdecColorTransform *trans, diff-tree 75e9e227691415642b037d6be0ff7c2ccc90772c (from ae5cb38d44ea9dabd46c38fd5231ef3afcfd86ac) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:32:33 2007 +0100 add 2 tests for DefineFunction diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am index 635e098..443cba2 100644 --- a/test/trace/Makefile.am +++ b/test/trace/Makefile.am @@ -42,6 +42,10 @@ EXTRA_DIST = \ currentframe.swf.trace \ double.swf \ double.swf.trace \ + function1.swf \ + function1.swf.trace \ + function2.swf \ + function2.swf.trace \ goto1.swf \ goto1.swf.trace \ goto2.swf \ diff --git a/test/trace/function1.swf b/test/trace/function1.swf new file mode 100755 index 0000000..63f85d4 Binary files /dev/null and b/test/trace/function1.swf differ diff --git a/test/trace/function1.swf.trace b/test/trace/function1.swf.trace new file mode 100755 index 0000000..8403c7e --- /dev/null +++ b/test/trace/function1.swf.trace @@ -0,0 +1,50 @@ +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 diff --git a/test/trace/function2.swf b/test/trace/function2.swf new file mode 100755 index 0000000..23a6b46 Binary files /dev/null and b/test/trace/function2.swf differ diff --git a/test/trace/function2.swf.trace b/test/trace/function2.swf.trace new file mode 100755 index 0000000..59c46d4 --- /dev/null +++ b/test/trace/function2.swf.trace @@ -0,0 +1,2 @@ +[type Function] +3 diff-tree ae5cb38d44ea9dabd46c38fd5231ef3afcfd86ac (from e2aa7731c273e897af818cadf20d5bb923d8c01e) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:30:41 2007 +0100 implement CallFunction, BitRShift, BitLShift and BitURShift includes some fixes like implementing the function with name case diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index c398e62..b172ec6 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -387,6 +387,33 @@ swfdec_action_call (JSContext *cx, guint return js_Invoke (cx, n_args, flags); } +/* FIXME: lots of overlap with swfdec_action_call_method */ +static JSBool +swfdec_action_call_function (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSStackFrame *fp = cx->fp; + const char *s; + guint32 n_args; + JSObject *obj; + jsval fun; + + s = swfdec_js_to_string (cx, fp->sp[-1]); + if (s == NULL) + return JS_FALSE; + if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args)) + return JS_FALSE; + if (n_args + 2 > (guint) (fp->sp - fp->spbase)) + return JS_FALSE; + + obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain); + if (!JS_GetProperty (cx, obj, s, &fun)) + return JS_FALSE; + fp->sp[-1] = fun; + fp->sp[-2] = OBJECT_TO_JSVAL (obj); + swfdec_action_call (cx, n_args, 0); + return JS_TRUE; +} + static JSBool swfdec_action_call_method (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -1207,7 +1234,9 @@ swfdec_action_define_function (JSContext } *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object); } else { - SWFDEC_ERROR ("FIXME: implement"); + jsval val = OBJECT_TO_JSVAL (fun->object); + if (!JS_SetProperty (cx, OBJ_THIS_OBJECT (cx, cx->fp->scopeChain), function_name, &val)) + return JS_FALSE; } /* update current context */ @@ -1215,6 +1244,36 @@ swfdec_action_define_function (JSContext return JS_TRUE; } +static JSBool +swfdec_action_shift (JSContext *cx, guint action, const guint8 *data, guint len) +{ + guint32 amount, value; + double d; + + if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &amount) || + !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &value)) + return JS_FALSE; + + amount &= 31; + switch (action) { + case 0x63: + d = value << amount; + break; + case 0x64: + d = ((gint) value) >> amount; + break; + case 0x65: + d = ((guint) value) >> amount; + break; + default: + g_assert_not_reached (); + return JS_FALSE; + } + + cx->fp->sp--; + return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1464,8 +1523,8 @@ static const SwfdecActionSpec actions[25 /* version 5 */ [0x3a] = { "Delete", NULL }, [0x3b] = { "Delete2", NULL }, - [0x3c] = { "DefineLocal", NULL }, - [0x3d] = { "CallFunction", NULL }, + [0x3c] = { "DefineLocal", NULL }, //, 2, 0, { NULL, NULL, swfdec_action_define_local, swfdec_action_define_local, swfdec_action_define_local } }, + [0x3d] = { "CallFunction", NULL, -1, 1, { NULL, NULL, swfdec_action_call_function, swfdec_action_call_function, swfdec_action_call_function } }, [0x3e] = { "Return", NULL }, [0x3f] = { "Modulo", NULL }, [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } }, @@ -1495,9 +1554,9 @@ static const SwfdecActionSpec actions[25 [0x60] = { "BitAnd", NULL }, [0x61] = { "BitOr", NULL }, [0x62] = { "BitXor", NULL }, - [0x63] = { "BitLShift", NULL }, - [0x64] = { "BitRShift", NULL }, - [0x65] = { "BitURShift", NULL }, + [0x63] = { "BitLShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, + [0x64] = { "BitRShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, + [0x65] = { "BitURShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, /* version 6 */ [0x66] = { "StrictEquals", NULL }, [0x67] = { "Greater", NULL, 2, 1, { NULL, NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, diff-tree e2aa7731c273e897af818cadf20d5bb923d8c01e (from ee7ecfa22195201642e114bfdb24d28aa690e00c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:29:46 2007 +0100 create a call object for calls to SWF code diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c index 1d15966..ce8d014 100644 --- a/libswfdec/js/jsinterp.c +++ b/libswfdec/js/jsinterp.c @@ -963,7 +963,10 @@ have_fun: } ok = js_Interpret(cx, &v); } else if (swf) { - frame.scopeChain = funobj; /* FIXME */ + if (!js_GetCallObject(cx, &frame, parent)) { + ok = JS_FALSE; + goto out; + } ok = swfdec_script_interpret(swf, cx, &v); } else { /* fun might be onerror trying to report a syntax error in itself. */ diff-tree ee7ecfa22195201642e114bfdb24d28aa690e00c (from 56d6b7a99657f96cc093d7136ff7eea4a6acfcfd) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:28:46 2007 +0100 return "[type Function]" from function.toString() diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c index 84121de..a085673 100644 --- a/libswfdec/js/jsfun.c +++ b/libswfdec/js/jsfun.c @@ -1418,7 +1418,12 @@ js_fun_toString(JSContext *cx, JSObject static JSBool fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - return js_fun_toString(cx, obj, 0, argc, argv, rval); + JSString *string = JS_InternString (cx, "[type Function]"); + + if (string == NULL) + return JS_FALSE; + *rval = STRING_TO_JSVAL (string); + return JS_TRUE; } #if JS_HAS_TOSOURCE diff-tree 56d6b7a99657f96cc093d7136ff7eea4a6acfcfd (from bd449d3ebe7adc1a6fc90beafef2f192a6c23ac4) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 14:54:17 2007 +0100 implement DefineFunction contains some changes to script handling that are required to make this work properly, like allowing scripts that don't end with a 0 action diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index e2ddcec..c398e62 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -36,6 +36,7 @@ #include "swfdec_player_internal.h" #include "swfdec_root_movie.h" #include "js/jsfun.h" +#include "js/jsscope.h" /*** CONSTANT POOLS ***/ @@ -1134,9 +1135,129 @@ swfdec_action_init_object (JSContext *cx return JS_TRUE; } +static JSBool +swfdec_action_define_function (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *function_name; + guint i, n_args, size; + SwfdecBits bits; + JSFunction *fun; + SwfdecScript *script; + + swfdec_bits_init_data (&bits, data, len); + function_name = swfdec_bits_get_string (&bits); + if (function_name == NULL) { + SWFDEC_ERROR ("could not parse function name"); + return JS_FALSE; + } + n_args = swfdec_bits_get_u16 (&bits); + if (*function_name == '\0') { + /* anonymous function */ + fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA, NULL, NULL); + } else { + /* named function */ + fun = JS_NewFunction (cx, NULL, n_args, 0, NULL, function_name); + } + if (fun == NULL) + return JS_FALSE; + for (i = 0; i < n_args; i++) { + JSAtom *atom; + const char *arg_name = swfdec_bits_get_string (&bits); + if (arg_name == NULL || *arg_name == '\0') { + SWFDEC_ERROR ("empty argument name not allowed"); + return JS_FALSE; + } + /* FIXME: check duplicate arguments */ + atom = js_Atomize (cx, arg_name, strlen (arg_name), 0); + if (atom == NULL) + return JS_FALSE; + if (!js_AddNativeProperty (cx, fun->object, (jsid) atom, + js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, + SPROP_HAS_SHORTID, i)) { + return JS_FALSE; + } + } + size = swfdec_bits_get_u16 (&bits); + /* check the script can be created */ + script = cx->fp->swf; + if (script->buffer->data + script->buffer->length < cx->fp->pc + 3 + len + size) { + SWFDEC_ERROR ("size of function is too big"); + return FALSE; + } else { + /* create the script */ + SwfdecBuffer *buffer = swfdec_buffer_new_subbuffer (script->buffer, + cx->fp->pc + 3 + len - script->buffer->data, size); + swfdec_bits_init (&bits, buffer); + script = swfdec_script_new_for_player (JS_GetContextPrivate (cx), + &bits, *function_name ? function_name : "<lambda>", + ((SwfdecScript *) cx->fp->swf)->version); + swfdec_buffer_unref (buffer); + } + if (script == NULL) { + SWFDEC_ERROR ("failed to create script"); + return JS_FALSE; + } + fun->swf = script; + /* attach the function */ + if (*function_name == '\0') { + if (action == 0) { + SWFDEC_ERROR ("not enough stack space available"); + return JS_FALSE; + } + *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object); + } else { + SWFDEC_ERROR ("FIXME: implement"); + } + + /* update current context */ + cx->fp->pc += 3 + len + size; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_define_function (guint action, const guint8 *data, guint len) +{ + SwfdecBits bits; + GString *string; + const char *function_name; + guint i, n_args, size; + + string = g_string_new ("DefineFunction "); + swfdec_bits_init_data (&bits, data, len); + function_name = swfdec_bits_get_string (&bits); + if (function_name == NULL) { + SWFDEC_ERROR ("could not parse function name"); + g_string_free (string, TRUE); + return NULL; + } + if (*function_name) { + g_string_append (string, function_name); + g_string_append_c (string, ' '); + } + n_args = swfdec_bits_get_u16 (&bits); + g_string_append_c (string, '('); + + for (i = 0; i < n_args; i++) { + const char *arg_name = swfdec_bits_get_string (&bits); + if (arg_name == NULL || *arg_name == '\0') { + SWFDEC_ERROR ("empty argument name not allowed"); + g_string_free (string, TRUE); + return NULL; + } + if (i) + g_string_append (string, ", "); + g_string_append (string, arg_name); + } + g_string_append_c (string, ')'); + size = swfdec_bits_get_u16 (&bits); + g_string_append_printf (string, " %u", size); + return g_string_free (string, FALSE); +} + +static char * swfdec_action_print_get_url (guint action, const guint8 *data, guint len) { SwfdecBits bits; @@ -1406,7 +1527,7 @@ static const SwfdecActionSpec actions[25 [0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } }, [0x9a] = { "GetURL2", NULL }, /* version 5 */ - [0x9b] = { "DefineFunction", NULL }, + [0x9b] = { "DefineFunction", swfdec_action_print_define_function, 0, -1, { NULL, NULL, swfdec_action_define_function, swfdec_action_define_function, swfdec_action_define_function } }, /* version 4 */ [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } }, [0x9e] = { "Call", NULL }, @@ -1442,7 +1563,7 @@ swfdec_script_foreach_internal (SwfdecBi gconstpointer bytecode; bytecode = bits->ptr; - while ((action = swfdec_bits_get_u8 (bits))) { + while (swfdec_bits_left (bits) && (action = swfdec_bits_get_u8 (bits))) { if (action & 0x80) { len = swfdec_bits_get_u16 (bits); data = bits->ptr; @@ -1634,8 +1755,10 @@ swfdec_script_interpret (SwfdecScript *s while (TRUE) { /* check pc */ + if (pc == endpc) /* needed for scripts created via DefineFunction */ + break; if (pc < startpc || pc >= endpc) { - SWFDEC_ERROR ("pc %p not in valid range [%p, %p] anymore", pc, startpc, endpc); + SWFDEC_ERROR ("pc %p not in valid range [%p, %p) anymore", pc, startpc, endpc); goto internal_error; } diff-tree bd449d3ebe7adc1a6fc90beafef2f192a6c23ac4 (from 2ae8e627b6ad7d5c5cba649db11cde9758e43815) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 14:52:20 2007 +0100 fix SwfdecScript reference handling - intitialize fun->swf to NULL - unref fun->swf on finalization diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c index 1ba58f8..84121de 100644 --- a/libswfdec/js/jsfun.c +++ b/libswfdec/js/jsfun.c @@ -1042,6 +1042,7 @@ fun_convert(JSContext *cx, JSObject *obj } } +extern void swfdec_script_unref (void *script); static void fun_finalize(JSContext *cx, JSObject *obj) { @@ -1058,6 +1059,8 @@ fun_finalize(JSContext *cx, JSObject *ob return; if (fun->script) js_DestroyScript(cx, fun->script); + if (fun->swf) + swfdec_script_unref (fun->swf); JS_free(cx, fun); } @@ -1928,6 +1931,7 @@ js_NewFunction(JSContext *cx, JSObject * fun->object = NULL; fun->native = native; fun->script = NULL; + fun->swf = NULL; fun->nargs = nargs; fun->extra = 0; fun->nvars = 0; diff-tree 2ae8e627b6ad7d5c5cba649db11cde9758e43815 (from 7b858d98456af8c801b9c346ef7abc8ebd4a0453) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 12:38:28 2007 +0100 check !JSVAL_IS_NULL in all JSVAL_IS_OBJECT checks diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 64f0746..e2ddcec 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -403,7 +403,7 @@ swfdec_action_call_method (JSContext *cx if (n_args + 3 > (guint) (fp->sp - fp->spbase)) return JS_FALSE; - if (!JSVAL_IS_OBJECT (fp->sp[-2])) + if (!JSVAL_IS_OBJECT (fp->sp[-2]) || JSVAL_IS_NULL (fp->sp[-2])) goto fail; obj = JSVAL_TO_OBJECT (fp->sp[-2]); if (s[0] == '\0') { @@ -689,7 +689,7 @@ swfdec_action_get_member (JSContext *cx, if (s == NULL) return JS_FALSE; - if (JSVAL_IS_OBJECT (cx->fp->sp[-2])) { + if (JSVAL_IS_OBJECT (cx->fp->sp[-2]) && !JSVAL_IS_NULL (cx->fp->sp[-2])) { if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-2]), s, &cx->fp->sp[-2])) return JS_FALSE; } else { @@ -708,7 +708,7 @@ swfdec_action_set_member (JSContext *cx, if (s == NULL) return JS_FALSE; - if (JSVAL_IS_OBJECT (cx->fp->sp[-3])) { + if (JSVAL_IS_OBJECT (cx->fp->sp[-3]) && !JSVAL_IS_NULL (cx->fp->sp[-3])) { if (!JS_SetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-3]), s, &cx->fp->sp[-1])) return JS_FALSE; } @@ -989,7 +989,7 @@ swfdec_action_set_target (JSContext *cx, } /* evaluate relative to this to not get trapped by previous SetTarget calls */ target = swfdec_js_eval (cx, cx->fp->thisp, (const char *) data); - if (!JSVAL_IS_OBJECT (target)) { + if (!JSVAL_IS_OBJECT (target) || JSVAL_IS_NULL (target)) { SWFDEC_WARNING ("target is not an object"); return JS_TRUE; } @@ -1003,7 +1003,7 @@ swfdec_action_set_target2 (JSContext *cx val = cx->fp->sp[-1]; cx->fp->sp--; - if (!JSVAL_IS_OBJECT (val)) { + if (!JSVAL_IS_OBJECT (val) || JSVAL_IS_NULL (val)) { SWFDEC_WARNING ("target is not an object"); return JS_TRUE; } @@ -1034,7 +1034,7 @@ swfdec_action_start_drag (JSContext *cx, fp->sp[-6] = fp->sp[-5]; fp->sp[-5] = tmp; } - if (!JSVAL_IS_OBJECT (fp->sp[-1])) { + if (!JSVAL_IS_OBJECT (fp->sp[-1]) || JSVAL_IS_NULL (fp->sp[-1])) { fp->sp -= n_args + 2; return JS_TRUE; } @@ -1084,7 +1084,7 @@ swfdec_action_new_object (JSContext *cx, } fp->sp[-1] = constructor; - if (!JSVAL_IS_OBJECT (constructor)) + if (!JSVAL_IS_OBJECT (constructor) || JSVAL_IS_NULL (constructor)) goto fail; object = JSVAL_TO_OBJECT (constructor); if (JS_GetClass (object) != &js_FunctionClass) diff-tree 7b858d98456af8c801b9c346ef7abc8ebd4a0453 (from abfaad4612d9129e2cf0de1402f623e22d356831) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 12:34:20 2007 +0100 catch a case where fun->script is accessed unconditionally diff --git a/libswfdec/js/jsobj.c b/libswfdec/js/jsobj.c index 2033c97..112bdc8 100644 --- a/libswfdec/js/jsobj.c +++ b/libswfdec/js/jsobj.c @@ -2356,6 +2356,8 @@ Detecting(JSContext *cx, jsbytecode *pc) JSAtom *atom; script = cx->fp->script; + if (script == NULL) + return JS_FALSE; for (endpc = script->code + script->length; pc < endpc; pc++) { /* General case: a branch or equality op follows the access. */ op = (JSOp) *pc; diff-tree abfaad4612d9129e2cf0de1402f623e22d356831 (from parents) Merge: d8b4748701572b483c96bbb4a66a6f026cd1c1d7 a7b8850adba4086c321e69c8933f6248b3de0803 Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 09:59:37 2007 +0100 Merge branch 'master' into interpreter diff-tree d8b4748701572b483c96bbb4a66a6f026cd1c1d7 (from 1986ae14a62fc9d28ac38f53621fadaf9b42877f) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 19:07:12 2007 +0100 implement InitObject action all tests pass now diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index b1f1a63..64f0746 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1105,6 +1105,35 @@ fail: return JS_TRUE; } +static JSBool +swfdec_action_init_object (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSStackFrame *fp = cx->fp; + JSObject *object; + guint i, n_args; + + if (!JS_ValueToECMAUint32 (cx, fp->sp[-1], &n_args)) + return JS_FALSE; + if ((guint) (fp->sp - fp->spbase) < 2 * n_args + 1) { + SWFDEC_ERROR ("not enough stack space"); + return JS_FALSE; + } + + object = JS_NewObject (cx, &js_ObjectClass, NULL, NULL); + if (object == NULL) + return JS_FALSE; + for (i = 0; i < n_args; i++) { + const char *s = swfdec_js_to_string (cx, fp->sp[-3 - 2 * i]); + if (s == NULL) + return JS_FALSE; + if (!JS_SetProperty (cx, object, s, &fp->sp[-2 - 2 * i])) + return JS_FALSE; + } + fp->sp -= 2 * n_args; + fp->sp[-1] = OBJECT_TO_JSVAL (object); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1321,7 +1350,7 @@ static const SwfdecActionSpec actions[25 [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } }, [0x41] = { "DefineLocal2", NULL }, [0x42] = { "InitArray", NULL }, - [0x43] = { "InitObject", NULL }, + [0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } }, [0x44] = { "Typeof", NULL }, [0x45] = { "TargetPath", NULL }, [0x46] = { "Enumerate", NULL }, diff-tree 1986ae14a62fc9d28ac38f53621fadaf9b42877f (from 7718526823b5db8d2d81c0caaed70500cb575c6f) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 18:15:06 2007 +0100 implement NewObject also fixes the constructors to work with it. 5/44 failures diff --git a/libswfdec/swfdec_js_color.c b/libswfdec/swfdec_js_color.c index a117118..ade8d6a 100644 --- a/libswfdec/swfdec_js_color.c +++ b/libswfdec/swfdec_js_color.c @@ -178,20 +178,16 @@ static JSBool swfdec_js_color_new (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { SwfdecMovie *movie; - JSObject *new; movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE); if (movie == NULL) { SWFDEC_INFO ("attempted to construct a color without a movie"); return JS_TRUE; } - new = JS_NewObject (cx, &color_class, NULL, NULL); - if (new == NULL) - return JS_TRUE; - if (!JS_SetPrivate (cx, new, movie)) + if (!JS_SetPrivate (cx, obj, movie)) return JS_TRUE; g_object_ref (movie); - *rval = OBJECT_TO_JSVAL (new); + *rval = OBJECT_TO_JSVAL (obj); return JS_TRUE; } diff --git a/libswfdec/swfdec_js_sound.c b/libswfdec/swfdec_js_sound.c index 67e11bd..b9f8d57 100644 --- a/libswfdec/swfdec_js_sound.c +++ b/libswfdec/swfdec_js_sound.c @@ -61,12 +61,7 @@ static JSClass sound_class = { static JSBool swfdec_js_sound_new (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - JSObject *new; - - new = JS_NewObject (cx, &sound_class, NULL, NULL); - if (new == NULL) - return JS_TRUE; - *rval = OBJECT_TO_JSVAL (new); + *rval = OBJECT_TO_JSVAL (obj); return JS_TRUE; } diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 8a0d3a6..b1f1a63 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -35,6 +35,7 @@ #include "swfdec_movie.h" #include "swfdec_player_internal.h" #include "swfdec_root_movie.h" +#include "js/jsfun.h" /*** CONSTANT POOLS ***/ @@ -1063,6 +1064,47 @@ swfdec_action_stop_sounds (JSContext *cx return JS_TRUE; } +static JSBool +swfdec_action_new_object (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSStackFrame *fp = cx->fp; + jsval constructor; + JSObject *object; + const JSClass *clasp; + guint n_args; + + constructor = fp->sp[-1]; + if (!swfdec_eval_jsval (cx, NULL, &constructor)) + return JS_FALSE; + if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args)) + return JS_FALSE; + if ((guint) (fp->sp - fp->spbase) < n_args + 2) { + SWFDEC_ERROR ("not enough stack space"); + return JS_FALSE; + } + fp->sp[-1] = constructor; + + if (!JSVAL_IS_OBJECT (constructor)) + goto fail; + object = JSVAL_TO_OBJECT (constructor); + if (JS_GetClass (object) != &js_FunctionClass) + goto fail; + clasp = ((JSFunction *) JS_GetPrivate (cx, object))->clasp; + object = JS_NewObject (cx, clasp, NULL, NULL); + if (object == NULL) + return JS_FALSE; + fp->sp[-2] = OBJECT_TO_JSVAL (object); + if (!swfdec_action_call (cx, n_args, JSINVOKE_CONSTRUCT)) + return JS_FALSE; + fp->sp[-1] = OBJECT_TO_JSVAL (object); + return JS_TRUE; + +fail: + fp->sp -= n_args + 1; + fp->sp[-1] = JSVAL_VOID; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1276,7 +1318,7 @@ static const SwfdecActionSpec actions[25 [0x3d] = { "CallFunction", NULL }, [0x3e] = { "Return", NULL }, [0x3f] = { "Modulo", NULL }, - [0x40] = { "NewObject", NULL }, + [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } }, [0x41] = { "DefineLocal2", NULL }, [0x42] = { "InitArray", NULL }, [0x43] = { "InitObject", NULL }, diff-tree 7718526823b5db8d2d81c0caaed70500cb575c6f (from 766926a5baf0ca465c0010f2cf157a41498cd841) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 12:35:59 2007 +0100 implement StopSounds diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 1decae7..8a0d3a6 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1054,6 +1054,15 @@ swfdec_action_end_drag (JSContext *cx, g return JS_TRUE; } +static JSBool +swfdec_action_stop_sounds (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecPlayer *player = JS_GetContextPrivate (cx); + + swfdec_player_stop_all_sounds (player); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1219,7 +1228,7 @@ static const SwfdecActionSpec actions[25 [0x06] = { "Play", NULL, 0, 0, { swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play } }, [0x07] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } }, [0x08] = { "ToggleQuality", NULL }, - [0x09] = { "StopSounds", NULL }, + [0x09] = { "StopSounds", NULL, 0, 0, { swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds } }, /* version 4 */ [0x0a] = { "Add", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, [0x0b] = { "Subtract", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, diff-tree 766926a5baf0ca465c0010f2cf157a41498cd841 (from e5233b84a86161a483eb16754dfd89f8f194b0d6) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 12:30:39 2007 +0100 implement StartDrag and EndDrag actions this makes speedball.swf work again diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 537fced..1decae7 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -359,23 +359,26 @@ swfdec_action_trace (JSContext *cx, guin * This function is similar to js_Invoke, however it uses a reversed stack * order. sp[-1] has to be the function to call, sp[-2] will be the object the * function is called on, sp[-3] is the first argument, followed by the rest of - * the arguments. The function reorders the stack on success and pushes the - * return value on top. + * the arguments. The function removes all of these argumends from the stack + * and pushes the return value on top. * * Returns: JS_TRUE on success, JS_FALSE on failure. **/ static JSBool swfdec_action_call (JSContext *cx, guint n_args, guint flags) { + JSStackFrame *fp = cx->fp; int i, j; jsval tmp; + g_assert ((guint) (fp->sp - fp->spbase) >= n_args + 2); + j = -1; i = - (n_args + 2); while (i < j) { - tmp = cx->fp->sp[j]; - cx->fp->sp[j] = cx->fp->sp[i]; - cx->fp->sp[i] = tmp; + tmp = fp->sp[j]; + fp->sp[j] = fp->sp[i]; + fp->sp[i] = tmp; j--; i++; } @@ -1006,6 +1009,51 @@ swfdec_action_set_target2 (JSContext *cx return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (val)); } +static JSBool +swfdec_action_start_drag (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSStackFrame *fp = cx->fp; + guint stack_size = fp->sp - fp->spbase; + guint n_args = 1; + + if (stack_size < 3) + return JS_FALSE; + if (!swfdec_eval_jsval (cx, NULL, &fp->sp[-1])) + return JS_FALSE; + if (swfdec_action_to_number (cx, fp->sp[-3])) { + jsval tmp; + if (stack_size < 7) + return JS_FALSE; + n_args = 5; + /* yay for order */ + tmp = fp->sp[-4]; + fp->sp[-4] = fp->sp[-7]; + fp->sp[-7] = tmp; + tmp = fp->sp[-6]; + fp->sp[-6] = fp->sp[-5]; + fp->sp[-5] = tmp; + } + if (!JSVAL_IS_OBJECT (fp->sp[-1])) { + fp->sp -= n_args + 2; + return JS_TRUE; + } + fp->sp[-3] = fp->sp[-2]; + fp->sp[-2] = fp->sp[-1]; + if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (fp->sp[-2]), "startDrag", &fp->sp[-1])) + return JS_FALSE; + swfdec_action_call (cx, n_args, 0); + fp->sp--; + return JS_TRUE; +} + +static JSBool +swfdec_action_end_drag (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecPlayer *player = JS_GetContextPrivate (cx); + swfdec_player_set_drag_movie (player, NULL, FALSE, NULL); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1196,8 +1244,8 @@ static const SwfdecActionSpec actions[25 [0x24] = { "CloneSprite", NULL }, [0x25] = { "RemoveSprite", NULL }, [0x26] = { "Trace", NULL, 1, 0, { NULL, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace } }, - [0x27] = { "StartDrag", NULL }, - [0x28] = { "EndDrag", NULL }, + [0x27] = { "StartDrag", NULL, -1, 0, { NULL, swfdec_action_start_drag, swfdec_action_start_drag, swfdec_action_start_drag, swfdec_action_start_drag } }, + [0x28] = { "EndDrag", NULL, 0, 0, { NULL, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag } }, [0x29] = { "StringLess", NULL }, /* version 7 */ [0x2a] = { "Throw", NULL }, diff-tree e5233b84a86161a483eb16754dfd89f8f194b0d6 (from 5a4bd5f45bc800d333c356097037c13d13152850) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 10:30:56 2007 +0100 various fixes to reference the correct this object diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index e501c4f..829c1ad 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -384,7 +384,7 @@ swfdec_js_eval_internal (JSContext *cx, if (cx->fp == NULL) goto out; g_assert (cx->fp->scopeChain); - cur = OBJECT_TO_JSVAL (cx->fp->scopeChain); + cur = OBJECT_TO_JSVAL (OBJ_THIS_OBJECT (cx, cx->fp->scopeChain)); } finish: diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index dca72e0..537fced 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -98,7 +98,9 @@ swfdec_constant_pool_free (SwfdecConstan static SwfdecMovie * swfdec_action_get_target (JSContext *cx) { - return swfdec_scriptable_from_jsval (cx, OBJECT_TO_JSVAL (cx->fp->scopeChain), SWFDEC_TYPE_MOVIE); + JSObject *object = cx->fp->scopeChain; + object = OBJ_THIS_OBJECT (cx, object); + return swfdec_scriptable_from_jsval (cx, OBJECT_TO_JSVAL (object), SWFDEC_TYPE_MOVIE); } static JSBool @@ -442,6 +444,8 @@ swfdec_eval_jsval (JSContext *cx, JSObje return JS_FALSE; *val = swfdec_js_eval (cx, obj, bytes); } else { + if (obj == NULL) + obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain); *val = OBJECT_TO_JSVAL (obj); } return JS_TRUE; diff-tree 5a4bd5f45bc800d333c356097037c13d13152850 (from 7f5416c27464e7f7f59444e8b2fff80eb65a43c2) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 22:17:14 2007 +0100 implement SetTarget and SetTarget2 diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 8f86eea..dca72e0 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -949,6 +949,59 @@ swfdec_action_equals2 (JSContext *cx, gu return JS_TRUE; } +static JSBool +swfdec_action_do_set_target (JSContext *cx, JSObject *target) +{ + JSObject *with; + + /* FIXME: this whole function stops working the moment it's used together + * with With */ + if (target == cx->fp->scopeChain) + return JS_TRUE; + if (target == cx->fp->thisp) { + /* FIXME: will probably break once SetTarget is called inside DefineFunctions */ + cx->fp->scopeChain = cx->fp->thisp; + return JS_TRUE; + } + with = js_NewObject(cx, &js_WithClass, target, cx->fp->scopeChain); + if (!with) + return JS_FALSE; + cx->fp->scopeChain = with; + return JS_TRUE; +} + +static JSBool +swfdec_action_set_target (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval target; + + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("SetTarget action does not specify a string"); + return JS_FALSE; + } + /* evaluate relative to this to not get trapped by previous SetTarget calls */ + target = swfdec_js_eval (cx, cx->fp->thisp, (const char *) data); + if (!JSVAL_IS_OBJECT (target)) { + SWFDEC_WARNING ("target is not an object"); + return JS_TRUE; + } + return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (target)); +} + +static JSBool +swfdec_action_set_target2 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval val; + + val = cx->fp->sp[-1]; + cx->fp->sp--; + if (!JSVAL_IS_OBJECT (val)) { + SWFDEC_WARNING ("target is not an object"); + return JS_TRUE; + } + return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (val)); +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1132,7 +1185,7 @@ static const SwfdecActionSpec actions[25 [0x18] = { "ToInteger", NULL }, [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } }, - [0x20] = { "SetTarget2", NULL }, + [0x20] = { "SetTarget22", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } }, [0x21] = { "StringAdd", NULL, 2, 1, { NULL, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add } }, [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } }, [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } }, @@ -1207,7 +1260,7 @@ static const SwfdecActionSpec actions[25 [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } }, /* version 3 */ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, - [0x8b] = { "SetTarget", NULL }, + [0x8b] = { "SetTarget", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, [0x8c] = { "GotoLabel", NULL }, /* version 4 */ [0x8d] = { "WaitForFrame2", NULL }, diff-tree 7f5416c27464e7f7f59444e8b2fff80eb65a43c2 (from 2f1ed9bb15785a9dfde7fdef1adc92346c11ab82) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 22:16:50 2007 +0100 didn't catch NULL here, oops diff --git a/libswfdec/swfdec_scriptable.c b/libswfdec/swfdec_scriptable.c index 479bad9..d1ff8da 100644 --- a/libswfdec/swfdec_scriptable.c +++ b/libswfdec/swfdec_scriptable.c @@ -144,6 +144,8 @@ swfdec_scriptable_from_jsval (JSContext if (!JSVAL_IS_OBJECT (val)) return NULL; + if (JSVAL_IS_NULL (val)) + return NULL; object = JSVAL_TO_OBJECT (val); klass = g_type_class_peek (type); if (klass == NULL) diff-tree 2f1ed9bb15785a9dfde7fdef1adc92346c11ab82 (from 2c8b93b57d2d93c187ac1e0c45667884047fc48d) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 20:53:14 2007 +0100 implement Equals2 and fix If and Goto to jump correctly 7/44 failures (all due to NewObject) diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index b736136..8f86eea 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -776,7 +776,7 @@ swfdec_action_jump (JSContext *cx, guint SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len); return JS_FALSE; } - cx->fp->pc += 4 + GINT16_FROM_LE (*((gint16*) data)); + cx->fp->pc += 5 + GINT16_FROM_LE (*((gint16*) data)); return JS_TRUE; } @@ -792,7 +792,7 @@ swfdec_action_if (JSContext *cx, guint a d = swfdec_action_to_number (cx, cx->fp->sp[-1]); cx->fp->sp--; if (d != 0) - cx->fp->pc += 4 + GINT16_FROM_LE (*((gint16*) data)); + cx->fp->pc += 5 + GINT16_FROM_LE (*((gint16*) data)); return JS_TRUE; } @@ -899,6 +899,56 @@ swfdec_action_less (JSContext *cx, guint return JS_TRUE; } +static JSBool +swfdec_action_equals2 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval rval, lval; + int ltag, rtag; + JSBool cond; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + ltag = JSVAL_TAG(lval); + rtag = JSVAL_TAG(rval); + if (ltag == rtag) { + if (ltag == JSVAL_STRING) { + cond = js_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)) == 0; + } else if (ltag == JSVAL_DOUBLE) { + cond = *JSVAL_TO_DOUBLE(lval) == *JSVAL_TO_DOUBLE(rval); + } else { + cond = lval == rval; + } + } else { + if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { + cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)); + } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { + cond = JS_FALSE; + } else { + if (ltag == JSVAL_OBJECT) { + if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT(lval), 0, &lval)) + return JS_FALSE; + ltag = JSVAL_TAG(lval); + } else if (rtag == JSVAL_OBJECT) { + if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT(rval), 0, &rval)) + return JS_FALSE; + rtag = JSVAL_TAG(rval); + } + if (ltag == JSVAL_STRING && rtag == JSVAL_STRING) { + cond = js_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)) == 0; + } else { + double d, d2; + if (!JS_ValueToNumber (cx, lval, &d) || + !JS_ValueToNumber (cx, rval, &d2)) + return JS_FALSE; + cond = d == d2; + } + } + } + cx->fp->sp--; + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (cond); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1121,7 +1171,7 @@ static const SwfdecActionSpec actions[25 [0x46] = { "Enumerate", NULL }, [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } }, [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, - [0x49] = { "Equals2", NULL }, + [0x49] = { "Equals2", NULL, 2, 1, { NULL, NULL, swfdec_action_equals2, swfdec_action_equals2, swfdec_action_equals2 } }, [0x4a] = { "ToNumber", NULL }, [0x4b] = { "ToString", NULL }, [0x4c] = { "PushDuplicate", NULL, 1, 2, { NULL, NULL, swfdec_action_push_duplicate, swfdec_action_push_duplicate, swfdec_action_push_duplicate } }, diff-tree 2c8b93b57d2d93c187ac1e0c45667884047fc48d (from 0a490e81dada959efc3ed155a98b8de577ff4dd2) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 20:52:23 2007 +0100 another fix for swfdec_js_internal This code is nasty, I seriously have to clean it up diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 62cf665..e501c4f 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -376,7 +376,7 @@ swfdec_js_eval_internal (JSContext *cx, if (!swfdec_js_eval_get_property (cx, obj, str, strlen (str), &cur)) goto out; } - str = NULL; + goto finish; } obj = JSVAL_TO_OBJECT (cur); } @@ -387,6 +387,7 @@ swfdec_js_eval_internal (JSContext *cx, cur = OBJECT_TO_JSVAL (cx->fp->scopeChain); } +finish: g_free (work); *val = cur; return TRUE; diff-tree 0a490e81dada959efc3ed155a98b8de577ff4dd2 (from 25d626bfbf646328e7209d72a6ebe73e1036b5b1) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 19:32:59 2007 +0100 implement ActionLess this includes a fix to swfdec_action_to_number since apparently Flash 4 pushes numbers as strings and converts them for numerical operations. 9/44 failures in the testsuite diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index acb34fa..b736136 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -29,6 +29,7 @@ #include "js/jsinterp.h" #include <string.h> +#include <math.h> #include "swfdec_decoder.h" #include "swfdec_js.h" #include "swfdec_movie.h" @@ -523,6 +524,11 @@ swfdec_action_to_number (JSContext *cx, return *JSVAL_TO_DOUBLE (val); } else if (JSVAL_IS_BOOLEAN (val)) { return JSVAL_TO_BOOLEAN (val); + } else if (JSVAL_IS_STRING (val)) { + double d; + if (!JS_ValueToNumber (cx, val, &d)) + return 0; + return isnan (d) ? 0 : d; } else { return 0; } @@ -872,6 +878,27 @@ swfdec_action_random_number (JSContext * return JS_NewNumberValue(cx, result, &cx->fp->sp[-1]); } +static JSBool +swfdec_action_less (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval rval, lval; + double l, r; + JSBool cond; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + l = swfdec_action_to_number (cx, lval); + r = swfdec_action_to_number (cx, rval); + cond = l < r; + cx->fp->sp--; + if (((SwfdecScript *) cx->fp->swf)->version < 5) { + cx->fp->sp[-1] = INT_TO_JSVAL (cond ? 1 : 0); + } else { + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (cond); + } + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1044,7 +1071,7 @@ static const SwfdecActionSpec actions[25 [0x0c] = { "Multiply", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, [0x0d] = { "Divide", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, [0x0e] = { "Equals", NULL }, - [0x0f] = { "Less", NULL }, + [0x0f] = { "Less", NULL, 2, 1, { NULL, swfdec_action_less, swfdec_action_less, swfdec_action_less, swfdec_action_less } }, [0x10] = { "And", NULL }, [0x11] = { "Or", NULL }, [0x12] = { "Not", NULL, 1, 1, { NULL, swfdec_action_not_4, swfdec_action_not_5, swfdec_action_not_5, swfdec_action_not_5 } }, diff-tree 25d626bfbf646328e7209d72a6ebe73e1036b5b1 (from ca7b42ca13e0758954f41e5f0dc673a90c07a89b) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 19:11:03 2007 +0100 stop printing out all actions That part of the code should work well enough now :) diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 0a40480..acb34fa 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1227,7 +1227,7 @@ validate_action (gconstpointer bytecode, return FALSE; } /* we might want to do stuff here for certain actions */ -#if 1 +#if 0 { char *foo = swfdec_script_print_action (action, data, len); if (foo == NULL) diff-tree ca7b42ca13e0758954f41e5f0dc673a90c07a89b (from 635f8982ba523747ac79bc87a4d106ba61ba3b44) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 19:04:42 2007 +0100 ints are ints not uints in Push action diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index a98b165..0a40480 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -260,8 +260,7 @@ swfdec_action_push (JSContext *cx, guint } case 7: /* 32bit int */ { - /* FIXME: spec says U32, do they mean this? */ - guint i = swfdec_bits_get_u32 (&bits); + int i = swfdec_bits_get_u32 (&bits); *cx->fp->sp++ = INT_TO_JSVAL (i); break; } @@ -954,7 +953,7 @@ swfdec_action_print_push (guint action, g_string_append_printf (string, "%g", swfdec_bits_get_double (&bits)); break; case 7: /* 32bit int */ - g_string_append_printf (string, "%u", swfdec_bits_get_u32 (&bits)); + g_string_append_printf (string, "%d", swfdec_bits_get_u32 (&bits)); break; case 8: /* 8bit ConstantPool address */ g_string_append_printf (string, "Pool %u", swfdec_bits_get_u8 (&bits)); diff-tree 635f8982ba523747ac79bc87a4d106ba61ba3b44 (from 56d1844f206f946a24755bdb03ccfafdb5c51571) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 19:00:06 2007 +0100 implement RandomNumber and PushDuplicate diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 22ada41..a98b165 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -849,6 +849,30 @@ swfdec_action_string_add (JSContext *cx, return JS_TRUE; } +static JSBool +swfdec_action_push_duplicate (JSContext *cx, guint action, const guint8 *data, guint len) +{ + cx->fp->sp++; + cx->fp->sp[-1] = cx->fp->sp[-2]; + return JS_TRUE; +} + +static JSBool +swfdec_action_random_number (JSContext *cx, guint action, const guint8 *data, guint len) +{ + gint32 max, result; + + if (!JS_ValueToECMAInt32 (cx, cx->fp->sp[-1], &max)) + return JS_FALSE; + + if (max <= 0) + result = 0; + else + result = g_random_int_range (0, max); + + return JS_NewNumberValue(cx, result, &cx->fp->sp[-1]); +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1047,7 +1071,7 @@ static const SwfdecActionSpec actions[25 [0x2b] = { "Cast", NULL }, [0x2c] = { "Implements", NULL }, /* version 4 */ - [0x30] = { "RandomNumber", NULL }, + [0x30] = { "RandomNumber", NULL, 1, 1, { NULL, swfdec_action_random_number, swfdec_action_random_number, swfdec_action_random_number, swfdec_action_random_number } }, [0x31] = { "MBStringLength", NULL }, [0x32] = { "CharToAscii", NULL }, [0x33] = { "AsciiToChar", NULL }, @@ -1074,7 +1098,7 @@ static const SwfdecActionSpec actions[25 [0x49] = { "Equals2", NULL }, [0x4a] = { "ToNumber", NULL }, [0x4b] = { "ToString", NULL }, - [0x4c] = { "PushDuplicate", NULL }, + [0x4c] = { "PushDuplicate", NULL, 1, 2, { NULL, NULL, swfdec_action_push_duplicate, swfdec_action_push_duplicate, swfdec_action_push_duplicate } }, [0x4d] = { "Swap", NULL }, [0x4e] = { "GetMember", NULL, 2, 1, { NULL, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member } }, [0x4f] = { "SetMember", NULL, 3, 0, { NULL, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member } }, diff-tree 56d1844f206f946a24755bdb03ccfafdb5c51571 (from ca1d6d627bbc5c221ae0ef51d5b7a1c573fe32e5) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 18:48:41 2007 +0100 implement naive Add2 for Flash 5 and 6 diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 7848e14..22ada41 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -580,6 +580,49 @@ swfdec_action_binary (JSContext *cx, gui return JS_NewNumberValue (cx, l, &cx->fp->sp[-1]); } +static JSString * +swfdec_action_to_string_5 (JSContext *cx, jsval val) +{ + if (JSVAL_IS_VOID (val) || JSVAL_IS_NULL (val)) + return cx->runtime->emptyString; + return js_ValueToString (cx, val); +} + +static JSBool +swfdec_action_add2_5 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval rval, lval; + gboolean cond; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) { + JSString *str, *str2; + if (cond) { + str = JSVAL_TO_STRING (lval); + if ((str2 = swfdec_action_to_string_5 (cx, rval)) == NULL) + return JS_FALSE; + } else { + str2 = JSVAL_TO_STRING (rval); + if ((str = swfdec_action_to_string_5 (cx, lval)) == NULL) + return JS_FALSE; + } + str = js_ConcatStrings (cx, str, str2); + if (!str) + return JS_FALSE; + cx->fp->sp--; + cx->fp->sp[-1] = STRING_TO_JSVAL (str); + } else { + double d, d2; + d = swfdec_action_to_number (cx, lval); + d2 = swfdec_action_to_number (cx, rval); + d += d2; + cx->fp->sp--; + return JS_NewNumberValue(cx, d, &cx->fp->sp[-1]); + } + return JS_TRUE; +} + static JSBool swfdec_action_add2_7 (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -1026,7 +1069,7 @@ static const SwfdecActionSpec actions[25 [0x44] = { "Typeof", NULL }, [0x45] = { "TargetPath", NULL }, [0x46] = { "Enumerate", NULL }, - [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, NULL, NULL, swfdec_action_add2_7 } }, + [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } }, [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, [0x49] = { "Equals2", NULL }, [0x4a] = { "ToNumber", NULL }, diff-tree ca1d6d627bbc5c221ae0ef51d5b7a1c573fe32e5 (from 10d7419e68981104fb2e59b6d3df874170a977f1) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 18:11:16 2007 +0100 implement alpha handling in a smarter way diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index 725ce74..23602c4 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -168,10 +168,18 @@ tag_func_define_bits_jpeg (SwfdecSwfDeco return SWFDEC_STATUS_OK; } +static gboolean +swfdec_image_has_alpha (SwfdecImage *image) +{ + return image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2 || + image->type == SWFDEC_IMAGE_TYPE_JPEG3; +} + static void -swfdec_image_create_surface (SwfdecImage *image, guint8 *data, gboolean has_alpha) +swfdec_image_create_surface (SwfdecImage *image, guint8 *data) { static const cairo_user_data_key_t key; + gboolean has_alpha = swfdec_image_has_alpha (image); g_assert (image->surface == NULL); @@ -204,7 +212,7 @@ swfdec_image_jpeg_load (SwfdecImage *ima jpeg_rgb_decoder_get_image (dec, &image_data, &image->rowstride, NULL, NULL); jpeg_rgb_decoder_free (dec); - swfdec_image_create_surface (image, image_data, FALSE); + swfdec_image_create_surface (image, image_data); SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); @@ -252,7 +260,7 @@ swfdec_image_jpeg2_load (SwfdecImage *im jpeg_rgb_decoder_get_image (dec, &image_data, &image->rowstride, &image->width, &image->height); jpeg_rgb_decoder_free (dec); - swfdec_image_create_surface (image, image_data, FALSE); + swfdec_image_create_surface (image, image_data); SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); @@ -317,7 +325,7 @@ swfdec_image_jpeg3_load (SwfdecImage *im merge_alpha (image, image_data, alpha_data); g_free (alpha_data); - swfdec_image_create_surface (image, image_data, TRUE); + swfdec_image_create_surface (image, image_data); SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); @@ -487,7 +495,7 @@ swfdec_image_lossless_load (SwfdecImage #endif } - swfdec_image_create_surface (image, image_data, have_alpha); + swfdec_image_create_surface (image, image_data); } int @@ -611,11 +619,7 @@ swfdec_image_get_surface_for_target (Swf /* FIXME: we might want to create multiple surfaces here if there's multiple * live rendering sources. Right now, this is the quick fix, that transforms * the cache to the most recent used type */ - if (cairo_surface_get_type (current) == CAIRO_SURFACE_TYPE_IMAGE && - cairo_image_surface_get_format (current) == CAIRO_FORMAT_RGB24) - content = CAIRO_CONTENT_COLOR; - else - content = CAIRO_CONTENT_COLOR_ALPHA; + content = swfdec_image_has_alpha (image) ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR; similar = cairo_surface_create_similar (target, content, image->width, image->height); diff-tree 10d7419e68981104fb2e59b6d3df874170a977f1 (from parents) Merge: bf21308d97b50d9867f2c084122e5fc0cfd85f6e 2cb8680a8577ff5d018b50e7da55c233e8eaa4af Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 15:02:44 2007 +0100 Merge branch 'master' into interpreter diff --cc libswfdec/swfdec_image.c index 2810291,0cf6502..725ce74 @@@ -484,10 -512,9 +484,10 @@@ } } } +#endif } - swfdec_image_create_surface (image, image_data); + swfdec_image_create_surface (image, image_data, have_alpha); } int diff-tree bf21308d97b50d9867f2c084122e5fc0cfd85f6e (from e06edd91cd480f68e8612517abac3aa7a287abab) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 28 14:52:16 2007 +0100 various fixes for the previous image decoding cleanups diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index c9df0de..2810291 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -117,7 +117,7 @@ lossless (const guint8 *zptr, int zlen, z.avail_out = len; ret = inflateInit (&z); - ret = inflate (&z, Z_SYNC_FLUSH); + ret = inflate (&z, Z_FINISH); if (ret != Z_STREAM_END) { SWFDEC_WARNING ("lossless: ret == %d", ret); } @@ -348,9 +348,8 @@ static void swfdec_image_lossless_load (SwfdecImage *image) { int format; - int color_table_size; + guint color_table_size; unsigned char *ptr; - unsigned char *endptr; SwfdecBits bits; unsigned char *image_data = NULL; int have_alpha = (image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2); @@ -377,66 +376,70 @@ swfdec_image_lossless_load (SwfdecImage if (image->width == 0 || image->height == 0) return; swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height); - ptr = lossless (bits.ptr, endptr - bits.ptr, image->width * image->height); - bits.ptr = endptr; if (format == 3) { - unsigned char *color_table; unsigned char *indexed_data; - int i; + guint i; + unsigned int rowstride = (image->width + 3) & ~3; image_data = g_malloc (4 * image->width * image->height); image->rowstride = image->width * 4; - color_table = g_malloc (color_table_size * 4); - if (have_alpha) { + ptr = lossless (bits.ptr, bits.end - bits.ptr, + color_table_size * 4 + rowstride * image->height); for (i = 0; i < color_table_size; i++) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN - color_table[i * 4 + 0] = ptr[i * 4 + 2]; - color_table[i * 4 + 1] = ptr[i * 4 + 1]; - color_table[i * 4 + 2] = ptr[i * 4 + 0]; - color_table[i * 4 + 3] = ptr[i * 4 + 3]; + guint8 tmp = ptr[i * 4 + 0]; + ptr[i * 4 + 0] = ptr[i * 4 + 2]; + ptr[i * 4 + 2] = tmp; #else - color_table[i * 4 + 0] = ptr[i * 4 + 3]; - color_table[i * 4 + 1] = ptr[i * 4 + 0]; - color_table[i * 4 + 2] = ptr[i * 4 + 1]; - color_table[i * 4 + 3] = ptr[i * 4 + 2]; + guint8 tmp = ptr[i * 4 + 3]; + ptr[i * 4 + 3] = ptr[i * 4 + 2]; + ptr[i * 4 + 2] = ptr[i * 4 + 1]; + ptr[i * 4 + 1] = ptr[i * 4 + 0]; + ptr[i * 4 + 0] = tmp; #endif } indexed_data = ptr + color_table_size * 4; } else { - for (i = 0; i < color_table_size; i++) { + ptr = lossless (bits.ptr, bits.end - bits.ptr, + color_table_size * 3 + rowstride * image->height); + for (i = color_table_size - 1; i < color_table_size; i--) { + guint8 color[3]; + color[0] = ptr[i * 3 + 0]; + color[1] = ptr[i * 3 + 1]; + color[2] = ptr[i * 3 + 2]; #if G_BYTE_ORDER == G_LITTLE_ENDIAN - color_table[i * 4 + 0] = ptr[i * 3 + 2]; - color_table[i * 4 + 1] = ptr[i * 3 + 1]; - color_table[i * 4 + 2] = ptr[i * 3 + 0]; - color_table[i * 4 + 3] = 255; + ptr[i * 4 + 0] = color[2]; + ptr[i * 4 + 1] = color[1]; + ptr[i * 4 + 2] = color[0]; + ptr[i * 4 + 3] = 255; #else - color_table[i * 4 + 0] = 255; - color_table[i * 4 + 1] = ptr[i * 3 + 0]; - color_table[i * 4 + 2] = ptr[i * 3 + 1]; - color_table[i * 4 + 3] = ptr[i * 3 + 2]; + ptr[i * 4 + 0] = 255; + ptr[i * 4 + 1] = color[0]; + ptr[i * 4 + 2] = color[1]; + ptr[i * 4 + 3] = color[2]; #endif } indexed_data = ptr + color_table_size * 3; } swfdec_image_colormap_decode (image, image_data, indexed_data, - color_table, color_table_size); + ptr, color_table_size); - g_free (color_table); g_free (ptr); } if (format == 4) { - unsigned char *p = ptr; int i, j; unsigned int c; unsigned char *idata; if (have_alpha) { SWFDEC_INFO("16bit images aren't allowed to have alpha, ignoring"); + have_alpha = FALSE; } + ptr = lossless (bits.ptr, bits.end - bits.ptr, 2 * image->width * image->height); image_data = g_malloc (4 * image->width * image->height); idata = image_data; image->rowstride = image->width * 4; @@ -444,7 +447,7 @@ swfdec_image_lossless_load (SwfdecImage /* 15 bit packed */ for (j = 0; j < image->height; j++) { for (i = 0; i < image->width; i++) { - c = p[1] | (p[0] << 8); + c = ptr[1] | (ptr[0] << 8); #if G_BYTE_ORDER == G_LITTLE_ENDIAN idata[0] = (c << 3) | ((c >> 2) & 0x7); idata[1] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); @@ -456,32 +459,32 @@ swfdec_image_lossless_load (SwfdecImage idata[1] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); idata[0] = 0xff; #endif - p += 2; + ptr += 2; idata += 4; } } g_free (ptr); } if (format == 5) { - int i, j; - image_data = ptr; + image_data = lossless (bits.ptr, bits.end - bits.ptr, 4 * image->width * image->height); image->rowstride = image->width * 4; - if (!have_alpha) { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + { + int i, j; /* image is stored in 0RGB format. We use ARGB/BGRA. */ for (j = 0; j < image->height; j++) { for (i = 0; i < image->width; i++) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN ptr[0] = ptr[3]; ptr[1] = ptr[2]; ptr[2] = ptr[1]; ptr[3] = 255; -#endif ptr += 4; } } } +#endif } swfdec_image_create_surface (image, image_data); diff-tree e06edd91cd480f68e8612517abac3aa7a287abab (from 6f0034ba32dd13577f1f2fb050734a7c55b4fdec) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 21:50:33 2007 +0100 fix "this" in swfdec_js_eval diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 68e89ff..62cf665 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -351,13 +351,14 @@ swfdec_js_eval_internal (JSContext *cx, work = swfdec_js_slash_to_dot (str); str = work; } - if (g_str_has_prefix (str, "this")) { + if (obj == NULL && g_str_has_prefix (str, "this")) { str += 4; if (*str == '.') str++; if (cx->fp == NULL) goto out; obj = cx->fp->thisp; + cur = OBJECT_TO_JSVAL (obj); } while (str != NULL && *str != '\0') { char *dot = strchr (str, '.'); diff-tree 6f0034ba32dd13577f1f2fb050734a7c55b4fdec (from db8da8e1714ce0839759c2fd0e65fbd6debf51fa) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 21:32:40 2007 +0100 use NULL in _eval of SetVariable and GetVariable to walk the scope chain diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index a3bb563..7848e14 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -316,7 +316,7 @@ swfdec_action_get_variable (JSContext *c s = swfdec_js_to_string (cx, cx->fp->sp[-1]); if (s == NULL) return JS_FALSE; - cx->fp->sp[-1] = swfdec_js_eval (cx, cx->fp->scopeChain, s); + cx->fp->sp[-1] = swfdec_js_eval (cx, NULL, s); return JS_TRUE; } @@ -329,7 +329,7 @@ swfdec_action_set_variable (JSContext *c if (s == NULL) return JS_FALSE; - swfdec_js_eval_set (cx, cx->fp->scopeChain, s, cx->fp->sp[-1]); + swfdec_js_eval_set (cx, NULL, s, cx->fp->sp[-1]); cx->fp->sp -= 2; return JS_TRUE; } diff-tree db8da8e1714ce0839759c2fd0e65fbd6debf51fa (from 2321fe755e190939f34b1d27b306a5270f17f43c) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 21:32:04 2007 +0100 more fixes for swfdec_eval when parsing the scope chain diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 84a1113..68e89ff 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -318,8 +318,6 @@ swfdec_js_eval_get_property (JSContext * return JS_FALSE; if (!prop) return JS_FALSE; - if (pobj) - obj = pobj; return OBJ_GET_PROPERTY (cx, obj, (jsid) prop->id, ret); } } @@ -345,7 +343,7 @@ static gboolean swfdec_js_eval_internal (JSContext *cx, JSObject *obj, const char *str, jsval *val, gboolean set) { - jsval cur; + jsval cur = JSVAL_NULL; char *work = NULL; SWFDEC_LOG ("eval called with \"%s\" on %p", str, obj); @@ -361,12 +359,10 @@ swfdec_js_eval_internal (JSContext *cx, goto out; obj = cx->fp->thisp; } - cur = OBJECT_TO_JSVAL (obj); while (str != NULL && *str != '\0') { char *dot = strchr (str, '.'); if (!JSVAL_IS_OBJECT (cur)) goto out; - obj = JSVAL_TO_OBJECT (cur); if (dot) { if (!swfdec_js_eval_get_property (cx, obj, str, dot - str, &cur)) goto out; @@ -381,6 +377,7 @@ swfdec_js_eval_internal (JSContext *cx, } str = NULL; } + obj = JSVAL_TO_OBJECT (cur); } if (obj == NULL) { if (cx->fp == NULL) diff-tree 2321fe755e190939f34b1d27b306a5270f17f43c (from 5fbaf958eeb90c6052933d2df118dc77fe18b15d) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 18:17:39 2007 +0100 avoid strdup in js_eval diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 9c01869..84a1113 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -300,13 +300,13 @@ fail: static JSBool swfdec_js_eval_get_property (JSContext *cx, JSObject *obj, - const char *name, jsval *ret) + const char *name, guint name_len, jsval *ret) { JSAtom *atom; JSObject *pobj; JSProperty *prop; - atom = js_Atomize (cx, name, strlen(name), 0); + atom = js_Atomize (cx, name, name_len, 0); if (!atom) return JS_FALSE; if (obj) { @@ -326,11 +326,11 @@ swfdec_js_eval_get_property (JSContext * static JSBool swfdec_js_eval_set_property (JSContext *cx, JSObject *obj, - const char *name, jsval *ret) + const char *name, guint name_len, jsval *ret) { JSAtom *atom; - atom = js_Atomize (cx, name, strlen(name), 0); + atom = js_Atomize (cx, name, name_len, 0); if (!atom) return JS_FALSE; if (obj == NULL) { @@ -368,17 +368,15 @@ swfdec_js_eval_internal (JSContext *cx, goto out; obj = JSVAL_TO_OBJECT (cur); if (dot) { - char *name = g_strndup (str, dot - str); - if (!swfdec_js_eval_get_property (cx, obj, name, &cur)) + if (!swfdec_js_eval_get_property (cx, obj, str, dot - str, &cur)) goto out; - g_free (name); str = dot + 1; } else { if (set) { - if (!swfdec_js_eval_set_property (cx, obj, str, val)) + if (!swfdec_js_eval_set_property (cx, obj, str, strlen (str), val)) goto out; } else { - if (!swfdec_js_eval_get_property (cx, obj, str, &cur)) + if (!swfdec_js_eval_get_property (cx, obj, str, strlen (str), &cur)) goto out; } str = NULL; diff-tree 5fbaf958eeb90c6052933d2df118dc77fe18b15d (from 6e0acc92fadc5b3ae1eaab51f3e16f3f96830e7a) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 18:15:16 2007 +0100 fix _eval to work with the empty string This is a regression fix diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 7111833..9c01869 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -384,6 +384,12 @@ swfdec_js_eval_internal (JSContext *cx, str = NULL; } } + if (obj == NULL) { + if (cx->fp == NULL) + goto out; + g_assert (cx->fp->scopeChain); + cur = OBJECT_TO_JSVAL (cx->fp->scopeChain); + } g_free (work); *val = cur; diff-tree 6e0acc92fadc5b3ae1eaab51f3e16f3f96830e7a (from ea89d7b542169e7173d93938041a16515b93c896) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 18:12:00 2007 +0100 set property on the right object diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 524707c..7111833 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -329,25 +329,16 @@ swfdec_js_eval_set_property (JSContext * const char *name, jsval *ret) { JSAtom *atom; - JSObject *pobj; - JSProperty *prop; atom = js_Atomize (cx, name, strlen(name), 0); if (!atom) return JS_FALSE; - if (obj) { - return OBJ_SET_PROPERTY (cx, obj, (jsid) atom, ret); - } else { + if (obj == NULL) { if (cx->fp == NULL || cx->fp->scopeChain == NULL) return JS_FALSE; - if (!js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) - return JS_FALSE; - if (!prop) - return JS_FALSE; - if (pobj) - obj = pobj; - return OBJ_SET_PROPERTY (cx, obj, (jsid) prop->id, ret); + obj = cx->fp->scopeChain; } + return OBJ_SET_PROPERTY (cx, obj, (jsid) atom, ret); } static gboolean diff-tree ea89d7b542169e7173d93938041a16515b93c896 (from 52828a39c261a28bf65734800692391b4f76b7c8) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 18:06:33 2007 +0100 makee debugging work again I don't like the debugging implementation in SpiderMonkey at all, since it's too intrusive, but oh well... diff --git a/libswfdec/Makefile.am b/libswfdec/Makefile.am index 7233f02..0216266 100644 --- a/libswfdec/Makefile.am +++ b/libswfdec/Makefile.am @@ -15,7 +15,6 @@ lib_LTLIBRARIES = libswfdec-@SWFDEC_MAJO js_cflags = -I$(srcdir)/js/ -I./js -DXP_UNIX -DDEBUG -# swfdec_debugger.c libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES = \ swfdec_audio.c \ swfdec_audio_event.c \ @@ -34,6 +33,7 @@ libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES swfdec_codec_screen.c \ swfdec_color.c \ swfdec_debug.c \ + swfdec_debugger.c \ swfdec_decoder.c \ swfdec_edittext.c \ swfdec_edittext_movie.c \ diff --git a/libswfdec/swfdec_debugger.c b/libswfdec/swfdec_debugger.c index 6123389..9a255b8 100644 --- a/libswfdec/swfdec_debugger.c +++ b/libswfdec/swfdec_debugger.c @@ -28,20 +28,36 @@ #include "swfdec_movie.h" #include "swfdec_player_internal.h" #include "js/jsdbgapi.h" +#include "js/jsinterp.h" /* for frame->swf */ /*** SwfdecDebuggerScript ***/ +static gboolean +swfdec_debugger_add_command (gconstpointer bytecode, guint action, + const guint8 *data, guint len, gpointer arrayp) +{ + SwfdecDebuggerCommand command; + + command.code = bytecode; + command.breakpoint = 0; + command.description = swfdec_script_print_action (action, data, len); + g_array_append_val (arrayp, command); + return TRUE; +} + static SwfdecDebuggerScript * -swfdec_debugger_script_new (JSScript *script, const char *name, - SwfdecDebuggerCommand *commands, guint n_commands) +swfdec_debugger_script_new (SwfdecScript *script) { + GArray *array; SwfdecDebuggerScript *ret; ret = g_new0 (SwfdecDebuggerScript, 1); ret->script = script; - ret->name = g_strdup (name); - ret->commands = commands; - ret->n_commands = n_commands; + swfdec_script_ref (script); + array = g_array_new (TRUE, FALSE, sizeof (SwfdecDebuggerCommand)); + swfdec_script_foreach (script, swfdec_debugger_add_command, array); + ret->n_commands = array->len; + ret->commands = (SwfdecDebuggerCommand *) g_array_free (array, FALSE); return ret; } @@ -49,7 +65,13 @@ swfdec_debugger_script_new (JSScript *sc static void swfdec_debugger_script_free (SwfdecDebuggerScript *script) { + guint i; + g_assert (script); + swfdec_script_unref (script->script); + for (i = 0; i < script->n_commands; i++) { + g_free (script->commands[i].description); + } g_free (script->commands); g_free (script); } @@ -131,17 +153,16 @@ swfdec_debugger_new (void) } void -swfdec_debugger_add_script (SwfdecDebugger *debugger, JSScript *jscript, const char *name, - SwfdecDebuggerCommand *commands, guint n_commands) +swfdec_debugger_add_script (SwfdecDebugger *debugger, SwfdecScript *script) { - SwfdecDebuggerScript *dscript = swfdec_debugger_script_new (jscript, name, commands, n_commands); + SwfdecDebuggerScript *dscript = swfdec_debugger_script_new (script); - g_hash_table_insert (debugger->scripts, jscript, dscript); + g_hash_table_insert (debugger->scripts, script, dscript); g_signal_emit (debugger, signals[SCRIPT_ADDED], 0, dscript); } SwfdecDebuggerScript * -swfdec_debugger_get_script (SwfdecDebugger *debugger, JSScript *script) +swfdec_debugger_get_script (SwfdecDebugger *debugger, SwfdecScript *script) { SwfdecDebuggerScript *dscript = g_hash_table_lookup (debugger->scripts, script); @@ -149,7 +170,7 @@ swfdec_debugger_get_script (SwfdecDebugg } void -swfdec_debugger_remove_script (SwfdecDebugger *debugger, JSScript *script) +swfdec_debugger_remove_script (SwfdecDebugger *debugger, SwfdecScript *script) { SwfdecDebuggerScript *dscript = g_hash_table_lookup (debugger->scripts, script); @@ -211,15 +232,43 @@ swfdec_debugger_do_breakpoint (SwfdecDeb } static JSTrapStatus -swfdec_debugger_handle_breakpoint (JSContext *cx, JSScript *script, jsbytecode *pc, - jsval *rval, void *closure) +swfdec_debugger_interrupt_cb (JSContext *cx, JSScript *script, + jsbytecode *pc, jsval *rval, void *debugger) { - SwfdecDebugger *debugger = JS_GetContextPrivate (cx); - - swfdec_debugger_do_breakpoint (debugger, GPOINTER_TO_UINT (closure)); + SwfdecDebuggerScript *dscript; + guint line; + if (!swfdec_debugger_get_current (debugger, &dscript, &line)) + return JSTRAP_CONTINUE; + if (dscript->commands[line].breakpoint) { + swfdec_debugger_do_breakpoint (debugger, dscript->commands[line].breakpoint); + } else if (SWFDEC_DEBUGGER (debugger)->stepping) { + swfdec_debugger_do_breakpoint (debugger, 0); + } return JSTRAP_CONTINUE; } +static void +swfdec_debugger_update_interrupting (SwfdecDebugger *debugger) +{ + guint i; + gboolean should_interrupt = debugger->stepping; + + for (i = 1; i < debugger->breakpoints->len && !should_interrupt; i++) { + Breakpoint *br = &g_array_index (debugger->breakpoints, Breakpoint, i); + + if (br->script) { + should_interrupt = TRUE; + break; + } + } + if (should_interrupt) { + JS_SetInterrupt (JS_GetRuntime (SWFDEC_PLAYER (debugger)->jscx), + swfdec_debugger_interrupt_cb, debugger); + } else { + JS_ClearInterrupt (JS_GetRuntime (SWFDEC_PLAYER (debugger)->jscx), NULL, NULL); + } +} + guint swfdec_debugger_set_breakpoint (SwfdecDebugger *debugger, SwfdecDebuggerScript *script, guint line) @@ -242,10 +291,6 @@ swfdec_debugger_set_breakpoint (SwfdecDe break; br = NULL; } - if (!JS_SetTrap (SWFDEC_PLAYER (debugger)->jscx, script->script, - script->commands[line].code, swfdec_debugger_handle_breakpoint, - GUINT_TO_POINTER (i + 1))) - return 0; if (br == NULL) { g_array_set_size (debugger->breakpoints, debugger->breakpoints->len + 1); @@ -255,6 +300,7 @@ swfdec_debugger_set_breakpoint (SwfdecDe br->script = script; br->line = line; script->commands[line].breakpoint = i + 1; + swfdec_debugger_update_interrupting (debugger); g_signal_emit (debugger, signals[BREAKPOINT_ADDED], 0, i + 1); return i + 1; } @@ -275,16 +321,15 @@ swfdec_debugger_unset_breakpoint (Swfdec if (br->script == NULL) return; - JS_ClearTrap (SWFDEC_PLAYER (debugger)->jscx, br->script->script, - br->script->commands[br->line].code, NULL, NULL); g_signal_emit (debugger, signals[BREAKPOINT_REMOVED], 0, id); br->script->commands[br->line].breakpoint = 0; br->script = NULL; + swfdec_debugger_update_interrupting (debugger); } static gboolean -swfdec_debugger_get_from_js (SwfdecDebugger *debugger, JSScript *script, jsbytecode *pc, - SwfdecDebuggerScript **script_out, guint *line_out) +swfdec_debugger_get_from_js (SwfdecDebugger *debugger, SwfdecScript *script, + jsbytecode *pc, SwfdecDebuggerScript **script_out, guint *line_out) { guint line; SwfdecDebuggerScript *dscript = swfdec_debugger_get_script (debugger, script); @@ -292,7 +337,7 @@ swfdec_debugger_get_from_js (SwfdecDebug if (dscript == NULL) return FALSE; for (line = 0; line < dscript->n_commands; line++) { - if (pc == (jsbytecode *) dscript->commands[line].code) { + if (pc == dscript->commands[line].code) { if (script_out) *script_out = dscript; if (line_out) @@ -311,16 +356,16 @@ swfdec_debugger_get_current (SwfdecDebug { JSStackFrame *frame = NULL; JSContext *cx; - JSScript *script; jsbytecode *pc; cx = SWFDEC_PLAYER (debugger)->jscx; JS_FrameIterator (cx, &frame); if (frame == NULL) return FALSE; - script = JS_GetFrameScript (cx, frame); + if (frame->swf == NULL) + return FALSE; pc = JS_GetFramePC (cx, frame); - return swfdec_debugger_get_from_js (debugger, script, pc, dscript, line); + return swfdec_debugger_get_from_js (debugger, frame->swf, pc, dscript, line); } gboolean @@ -358,15 +403,6 @@ swfdec_debugger_get_n_breakpoints (Swfde return debugger->breakpoints->len; } -static JSTrapStatus -swfdec_debugger_interrupt_cb (JSContext *cx, JSScript *script, - jsbytecode *pc, jsval *rval, void *debugger) -{ - if (swfdec_debugger_get_current (debugger, NULL, NULL)) - swfdec_debugger_do_breakpoint (debugger, 0); - return JSTRAP_CONTINUE; -} - void swfdec_debugger_set_stepping (SwfdecDebugger *debugger, gboolean stepping) { @@ -375,12 +411,6 @@ swfdec_debugger_set_stepping (SwfdecDebu if (debugger->stepping == stepping) return; debugger->stepping = stepping; - if (stepping) { - JS_SetInterrupt (JS_GetRuntime (SWFDEC_PLAYER (debugger)->jscx), - swfdec_debugger_interrupt_cb, debugger); - } else { - JS_ClearInterrupt (JS_GetRuntime (SWFDEC_PLAYER (debugger)->jscx), NULL, NULL); - } } gboolean diff --git a/libswfdec/swfdec_debugger.h b/libswfdec/swfdec_debugger.h index bd54f9f..7c87604 100644 --- a/libswfdec/swfdec_debugger.h +++ b/libswfdec/swfdec_debugger.h @@ -23,8 +23,8 @@ #include <glib-object.h> #include <libswfdec/swfdec.h> #include <libswfdec/swfdec_player_internal.h> +#include <libswfdec/swfdec_script.h> #include <libswfdec/swfdec_types.h> -#include <libswfdec/js/jsapi.h> G_BEGIN_DECLS @@ -41,14 +41,13 @@ typedef struct _SwfdecDebuggerCommand Sw #define SWFDEC_DEBUGGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_DEBUGGER, SwfdecDebuggerClass)) struct _SwfdecDebuggerCommand { - gpointer code; /* pointer to start bytecode in JScript */ + gconstpointer code; /* pointer to start bytecode in SwfdecScript */ guint breakpoint; /* id of breakpoint pointing here */ char * description; /* string describing the action */ }; struct _SwfdecDebuggerScript { - JSScript * script; /* the script */ - char * name; /* descriptive name of script */ + SwfdecScript * script; /* the script */ SwfdecDebuggerCommand *commands; /* commands executed in the script (NULL-terminated) */ guint n_commands; /* number of commands */ }; @@ -88,14 +87,11 @@ void swfdec_debugger_set_stepping (Swf gboolean swfdec_debugger_get_stepping (SwfdecDebugger * debugger); void swfdec_debugger_add_script (SwfdecDebugger * debugger, - JSScript * script, - const char * name, - SwfdecDebuggerCommand *commands, - guint n_commands); + SwfdecScript * script); SwfdecDebuggerScript * swfdec_debugger_get_script (SwfdecDebugger * debugger, - JSScript * script); + SwfdecScript * script); void swfdec_debugger_remove_script (SwfdecDebugger * debugger, - JSScript * script); + SwfdecScript * script); void swfdec_debugger_foreach_script (SwfdecDebugger * debugger, GFunc func, gpointer data); diff --git a/libswfdec/swfdec_event.c b/libswfdec/swfdec_event.c index 7ed820b..d988ad3 100644 --- a/libswfdec/swfdec_event.c +++ b/libswfdec/swfdec_event.c @@ -146,7 +146,7 @@ swfdec_event_list_parse (SwfdecEventList event.key = key; name = g_strconcat (description, ".", swfdec_event_list_condition_name (conditions), NULL); - event.script = swfdec_script_new (bits, name, version); + event.script = swfdec_script_new_for_player (list->player, bits, name, version); g_free (name); if (event.script) g_array_append_val (list->events, event); diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index e5c205f..a3bb563 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -23,6 +23,7 @@ #include "swfdec_script.h" #include "swfdec_debug.h" +#include "swfdec_debugger.h" #include "swfdec_scriptable.h" #include "js/jscntxt.h" #include "js/jsinterp.h" @@ -1105,13 +1106,14 @@ swfdec_script_print_action (guint action } } -typedef gboolean (* SwfdecScriptForeachFunc) (guint action, const guint8 *data, guint len, gpointer user_data); static gboolean -swfdec_script_foreach (SwfdecBits *bits, SwfdecScriptForeachFunc func, gpointer user_data) +swfdec_script_foreach_internal (SwfdecBits *bits, SwfdecScriptForeachFunc func, gpointer user_data) { guint action, len; const guint8 *data; + gconstpointer bytecode; + bytecode = bits->ptr; while ((action = swfdec_bits_get_u8 (bits))) { if (action & 0x80) { len = swfdec_bits_get_u16 (bits); @@ -1124,16 +1126,29 @@ swfdec_script_foreach (SwfdecBits *bits, SWFDEC_ERROR ("script too short"); return FALSE; } - if (!func (action, data, len, user_data)) + if (!func (bytecode, action, data, len, user_data)) return FALSE; + bytecode = bits->ptr; } return TRUE; } /*** PUBLIC API ***/ +gboolean +swfdec_script_foreach (SwfdecScript *script, SwfdecScriptForeachFunc func, gpointer user_data) +{ + SwfdecBits bits; + + g_return_val_if_fail (script != NULL, FALSE); + g_return_val_if_fail (func != NULL, FALSE); + + swfdec_bits_init (&bits, script->buffer); + return swfdec_script_foreach_internal (&bits, func, user_data); +} + static gboolean -validate_action (guint action, const guint8 *data, guint len, gpointer scriptp) +validate_action (gconstpointer bytecode, guint action, const guint8 *data, guint len, gpointer scriptp) { SwfdecScript *script = scriptp; int version = EXTRACT_VERSION (script->version); @@ -1158,12 +1173,30 @@ validate_action (guint action, const gui } SwfdecScript * +swfdec_script_new_for_player (SwfdecPlayer *player, SwfdecBits *bits, + const char *name, unsigned int version) +{ + SwfdecScript *script; + + g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL); + g_return_val_if_fail (bits != NULL, NULL); + + script = swfdec_script_new (bits, name, version); + if (SWFDEC_IS_DEBUGGER (player) && script) { + swfdec_debugger_add_script (SWFDEC_DEBUGGER (player), script); + script->debugger = player; + } + return script; +} + +SwfdecScript * swfdec_script_new (SwfdecBits *bits, const char *name, unsigned int version) { SwfdecScript *script; const guchar *start; g_return_val_if_fail (bits != NULL, NULL); + if (version < MINSCRIPTVERSION) { SWFDEC_ERROR ("swfdec version %u doesn't support scripts", version); return NULL; @@ -1176,7 +1209,7 @@ swfdec_script_new (SwfdecBits *bits, con script->name = g_strdup (name ? name : "Unnamed script"); script->version = version; - if (!swfdec_script_foreach (bits, validate_action, script)) { + if (!swfdec_script_foreach_internal (bits, validate_action, script)) { /* assign a random buffer here so we have something to unref */ script->buffer = bits->buffer; swfdec_buffer_ref (script->buffer); @@ -1203,6 +1236,11 @@ swfdec_script_unref (SwfdecScript *scrip g_return_if_fail (script->refcount > 0); script->refcount--; + if (script->refcount == 1 && script->debugger) { + script->debugger = NULL; + swfdec_debugger_remove_script (script->debugger, script); + return; + } if (script->refcount > 0) return; @@ -1266,13 +1304,37 @@ swfdec_script_interpret (SwfdecScript *s goto out; } - /* only valid return value */ while (TRUE) { /* check pc */ if (pc < startpc || pc >= endpc) { SWFDEC_ERROR ("pc %p not in valid range [%p, %p] anymore", pc, startpc, endpc); goto internal_error; } + + /* run interrupt handler */ + if (cx->runtime->interruptHandler) { + jsval tmp; + switch (cx->runtime->interruptHandler (cx, NULL, pc, &tmp, + cx->runtime->interruptHandlerData)) { + case JSTRAP_ERROR: + ok = JS_FALSE; + goto out; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = tmp; + goto out; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = tmp; + ok = JS_FALSE; + goto out; + default: + g_assert_not_reached (); + break; + } + } + /* decode next action */ action = *pc; spec = actions + action; @@ -1433,3 +1495,4 @@ swfdec_script_execute (SwfdecScript *scr return ok ? frame.rval : JSVAL_VOID; } + diff --git a/libswfdec/swfdec_script.h b/libswfdec/swfdec_script.h index d8688c3..1cea4a7 100644 --- a/libswfdec/swfdec_script.h +++ b/libswfdec/swfdec_script.h @@ -29,17 +29,25 @@ G_BEGIN_DECLS //typedef struct _SwfdecScript SwfdecScript; +typedef gboolean (* SwfdecScriptForeachFunc) (gconstpointer bytecode, guint action, + const guint8 *data, guint len, gpointer user_data); + /* FIXME: May want to typedef to SwfdecBuffer directly */ struct _SwfdecScript { SwfdecBuffer * buffer; /* buffer holding the script */ unsigned int refcount; /* reference count */ char * name; /* name identifying this script */ unsigned int version; /* version of the script */ + gpointer debugger; /* debugger owning us or NULL */ }; SwfdecScript * swfdec_script_new (SwfdecBits * bits, const char * name, unsigned int version); +SwfdecScript * swfdec_script_new_for_player (SwfdecPlayer * player, + SwfdecBits * bits, + const char * name, + unsigned int version); void swfdec_script_ref (SwfdecScript * script); void swfdec_script_unref (SwfdecScript * script); @@ -49,9 +57,13 @@ JSBool swfdec_script_interpret (Swfdec jsval swfdec_script_execute (SwfdecScript * script, SwfdecScriptable * scriptable); +gboolean swfdec_script_foreach (SwfdecScript * script, + SwfdecScriptForeachFunc func, + gpointer user_data); char * swfdec_script_print_action (guint action, const guint8 * data, guint len); + G_END_DECLS #endif diff --git a/libswfdec/swfdec_tag.c b/libswfdec/swfdec_tag.c index 3896101..e7c8aa8 100644 --- a/libswfdec/swfdec_tag.c +++ b/libswfdec/swfdec_tag.c @@ -297,7 +297,7 @@ tag_func_do_action (SwfdecSwfDecoder * s name = g_strdup_printf ("Sprite%u.Frame%u", SWFDEC_CHARACTER (s->parse_sprite)->id, s->parse_sprite->parse_frame); - script = swfdec_script_new (&s->b, name, s->version); + script = swfdec_script_new_for_player (SWFDEC_DECODER (s)->player, &s->b, name, s->version); g_free (name); if (script) swfdec_sprite_add_action (s->parse_sprite, s->parse_sprite->parse_frame, diff --git a/player/swfdec_debug_scripts.c b/player/swfdec_debug_scripts.c index 89bebce..3877da8 100644 --- a/player/swfdec_debug_scripts.c +++ b/player/swfdec_debug_scripts.c @@ -40,7 +40,7 @@ add_row (gpointer scriptp, gpointer stor gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, COLUMN_SCRIPT, script, - COLUMN_NAME, script->name, -1); + COLUMN_NAME, script->script->name, -1); } static void diff --git a/player/swfdec_player_manager.c b/player/swfdec_player_manager.c index d51e49b..82d55ed 100644 --- a/player/swfdec_player_manager.c +++ b/player/swfdec_player_manager.c @@ -137,7 +137,7 @@ swfdec_player_manager_class_init (Swfdec signals[MESSAGE] = g_signal_new ("message", G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__UINT_POINTER, /* FIXME */ - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER); } static void @@ -458,7 +458,7 @@ command_break (SwfdecPlayerManager *mana guint id = swfdec_debugger_set_breakpoint (SWFDEC_DEBUGGER (manager->player), manager->interrupt_script, line); swfdec_player_manager_output (manager, "%u: %s line %u: %s", - id, manager->interrupt_script->name, line, + id, manager->interrupt_script->script->name, line, manager->interrupt_script->commands[line].description); } else { swfdec_player_manager_error (manager, @@ -494,7 +494,7 @@ command_breakpoints (SwfdecPlayerManager for (i = 1; i <= n; i++) { if (swfdec_debugger_get_breakpoint (debugger, i, &script, &line)) { swfdec_player_manager_output (manager, "%u: %s line %u: %s", - i, script->name, line, script->commands[line].description); + i, script->script->name, line, script->commands[line].description); } } } @@ -552,7 +552,7 @@ do_find (gpointer scriptp, gpointer data for (i = 0; i < script->n_commands; i++) { if (strstr (script->commands[i].description, data->string)) { swfdec_player_manager_output (data->manager, "%s %u: %s", - script->name, i, script->commands[i].description); + script->script->name, i, script->commands[i].description); } } } diff-tree 52828a39c261a28bf65734800692391b4f76b7c8 (from b8b6df20af7044cda18cfde12662492f2903ecb0) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 18:05:39 2007 +0100 use automatic hscrollbars, too diff --git a/player/swfdebug.c b/player/swfdebug.c index 2f041f1..490814e 100644 --- a/player/swfdebug.c +++ b/player/swfdebug.c @@ -214,7 +214,7 @@ view_swf (SwfdecPlayer *player, double s scroll = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 0); scripts = swfdec_debug_scripts_new (SWFDEC_DEBUGGER (player)); gtk_container_add (GTK_CONTAINER (scroll), scripts); @@ -251,7 +251,7 @@ view_swf (SwfdecPlayer *player, double s scroll = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (hbox), scroll, TRUE, TRUE, 0); widget = swfdec_debug_script_new (SWFDEC_DEBUGGER (player)); gtk_container_add (GTK_CONTAINER (scroll), widget); diff-tree b8b6df20af7044cda18cfde12662492f2903ecb0 (from fc10e6599a2821de28900eb4f570654e4fe1958a) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 26 10:03:05 2007 +0100 rework case sensitivity once again - this time making it global and set only on startup I really should do a testsuite with embedding movies and testing their case sensitivity so I know what the official Flash player does diff --git a/libswfdec/js/jsatom.c b/libswfdec/js/jsatom.c index c4c85b7..f0816b2 100644 --- a/libswfdec/js/jsatom.c +++ b/libswfdec/js/jsatom.c @@ -673,10 +673,10 @@ out: JSAtom * js_AtomizeString(JSContext *cx, JSString *str, uintN flags) { - if (flags & ATOM_NOCASE) - return js_AtomizeStringWithCompare (cx, str, flags, js_compare_atom_keys_no_case); - else + if (cx->caseSensitive) return js_AtomizeStringWithCompare (cx, str, flags, js_compare_atom_keys); + else + return js_AtomizeStringWithCompare (cx, str, flags, js_compare_atom_keys_no_case); } JS_FRIEND_API(JSAtom *) diff --git a/libswfdec/js/jsatom.h b/libswfdec/js/jsatom.h index d9d2025..6f486c3 100644 --- a/libswfdec/js/jsatom.h +++ b/libswfdec/js/jsatom.h @@ -58,7 +58,6 @@ JS_BEGIN_EXTERN_C #define ATOM_PINNED 0x01 /* atom is pinned against GC */ #define ATOM_INTERNED 0x02 /* pinned variant for JS_Intern* API */ #define ATOM_MARK 0x04 /* atom is reachable via GC */ -#define ATOM_NOCASE 0x20 /* treat atom case-insensitive */ #define ATOM_NOCOPY 0x40 /* don't copy atom string bytes */ #define ATOM_TMPSTR 0x80 /* internal, to avoid extra string */ diff --git a/libswfdec/swfdec_edittext_movie.c b/libswfdec/swfdec_edittext_movie.c index e3d2119..421f6bc 100644 --- a/libswfdec/swfdec_edittext_movie.c +++ b/libswfdec/swfdec_edittext_movie.c @@ -80,7 +80,7 @@ swfdec_edit_text_movie_iterate (SwfdecMo jsobj = swfdec_scriptable_get_object (parent); if (jsobj == NULL) return; - val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable, FALSE); + val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable); if (JSVAL_IS_VOID (val)) return; @@ -110,7 +110,7 @@ swfdec_edit_text_movie_init_movie (Swfde if (jsobj == NULL) return; if (text->text->variable_prefix) { - val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable_prefix, FALSE); + val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable_prefix); if (!JSVAL_IS_OBJECT (val)) return; jsobj = JSVAL_TO_OBJECT (val); diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 1601b4b..524707c 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -300,18 +300,20 @@ fail: static JSBool swfdec_js_eval_get_property (JSContext *cx, JSObject *obj, - const char *name, gboolean initial, gboolean ignore_case, jsval *ret) + const char *name, jsval *ret) { JSAtom *atom; JSObject *pobj; JSProperty *prop; - atom = js_Atomize (cx, name, strlen(name), ignore_case ? ATOM_NOCASE : 0); + atom = js_Atomize (cx, name, strlen(name), 0); if (!atom) return JS_FALSE; - if (initial) { + if (obj) { return OBJ_GET_PROPERTY (cx, obj, (jsid) atom, ret); } else { + if (cx->fp == NULL || cx->fp->scopeChain == NULL) + return JS_FALSE; if (!js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) return JS_FALSE; if (!prop) @@ -324,18 +326,20 @@ swfdec_js_eval_get_property (JSContext * static JSBool swfdec_js_eval_set_property (JSContext *cx, JSObject *obj, - const char *name, gboolean initial, gboolean ignore_case, jsval *ret) + const char *name, jsval *ret) { JSAtom *atom; JSObject *pobj; JSProperty *prop; - atom = js_Atomize (cx, name, strlen(name), ignore_case ? ATOM_NOCASE : 0); + atom = js_Atomize (cx, name, strlen(name), 0); if (!atom) return JS_FALSE; - if (initial) { + if (obj) { return OBJ_SET_PROPERTY (cx, obj, (jsid) atom, ret); } else { + if (cx->fp == NULL || cx->fp->scopeChain == NULL) + return JS_FALSE; if (!js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) return JS_FALSE; if (!prop) @@ -348,23 +352,25 @@ swfdec_js_eval_set_property (JSContext * static gboolean swfdec_js_eval_internal (JSContext *cx, JSObject *obj, const char *str, - gboolean ignore_case, jsval *val, gboolean set) + jsval *val, gboolean set) { jsval cur; char *work = NULL; - gboolean initial = TRUE; SWFDEC_LOG ("eval called with \"%s\" on %p", str, obj); if (strchr (str, '/')) { work = swfdec_js_slash_to_dot (str); str = work; } - cur = OBJECT_TO_JSVAL (obj); if (g_str_has_prefix (str, "this")) { str += 4; if (*str == '.') str++; + if (cx->fp == NULL) + goto out; + obj = cx->fp->thisp; } + cur = OBJECT_TO_JSVAL (obj); while (str != NULL && *str != '\0') { char *dot = strchr (str, '.'); if (!JSVAL_IS_OBJECT (cur)) @@ -372,21 +378,20 @@ swfdec_js_eval_internal (JSContext *cx, obj = JSVAL_TO_OBJECT (cur); if (dot) { char *name = g_strndup (str, dot - str); - if (!swfdec_js_eval_get_property (cx, obj, name, initial, ignore_case, &cur)) + if (!swfdec_js_eval_get_property (cx, obj, name, &cur)) goto out; g_free (name); str = dot + 1; } else { if (set) { - if (!swfdec_js_eval_set_property (cx, obj, str, initial, ignore_case, val)) + if (!swfdec_js_eval_set_property (cx, obj, str, val)) goto out; } else { - if (!swfdec_js_eval_get_property (cx, obj, str, initial, ignore_case, &cur)) + if (!swfdec_js_eval_get_property (cx, obj, str, &cur)) goto out; } str = NULL; } - initial = FALSE; } g_free (work); @@ -403,7 +408,6 @@ out: * @cx: a #JSContext * @obj: #JSObject to use as a source for evaluating * @str: The string to evaluate - * @ignore_case: TRUE for case insensitive evaluation * * This function works like the Actionscript eval function used on @obj. * It handles both slash-style and dot-style notation. @@ -411,23 +415,24 @@ out: * Returns: the value or JSVAL_VOID if no value was found. **/ jsval -swfdec_js_eval (JSContext *cx, JSObject *obj, const char *str, - gboolean ignore_case) +swfdec_js_eval (JSContext *cx, JSObject *obj, const char *str) { jsval ret; g_return_val_if_fail (cx != NULL, JSVAL_VOID); - g_return_val_if_fail (obj != NULL, JSVAL_VOID); g_return_val_if_fail (str != NULL, JSVAL_VOID); - if (!swfdec_js_eval_internal (cx, obj, str, ignore_case, &ret, FALSE)) + if (!swfdec_js_eval_internal (cx, obj, str, &ret, FALSE)) ret = JSVAL_VOID; return ret; } void swfdec_js_eval_set (JSContext *cx, JSObject *obj, const char *str, - jsval val, gboolean ignore_case) + jsval val) { - swfdec_js_eval_internal (cx, obj, str, ignore_case, &val, TRUE); + g_return_if_fail (cx != NULL); + g_return_if_fail (str != NULL); + + swfdec_js_eval_internal (cx, obj, str, &val, TRUE); } diff --git a/libswfdec/swfdec_js.h b/libswfdec/swfdec_js.h index ea49a72..5e58152 100644 --- a/libswfdec/swfdec_js.h +++ b/libswfdec/swfdec_js.h @@ -49,13 +49,11 @@ void swfdec_js_movie_remove_property (S char * swfdec_js_slash_to_dot (const char * slash_str); jsval swfdec_js_eval (JSContext * cx, JSObject * obj, - const char * str, - gboolean ignore_case); + const char * str); void swfdec_js_eval_set (JSContext * cx, JSObject * obj, const char * str, - jsval val, - gboolean ignore_case); + jsval val); /* support functions */ const char * swfdec_js_to_string (JSContext * cx, diff --git a/libswfdec/swfdec_js_global.c b/libswfdec/swfdec_js_global.c index 27522c1..328d74d 100644 --- a/libswfdec/swfdec_js_global.c +++ b/libswfdec/swfdec_js_global.c @@ -33,7 +33,7 @@ swfdec_js_global_eval (JSContext *cx, JS const char *bytes = swfdec_js_to_string (cx, argv[0]); if (bytes == NULL) return JS_FALSE; - *rval = swfdec_js_eval (cx, obj, bytes, FALSE); + *rval = swfdec_js_eval (cx, obj, bytes); } else { *rval = argv[0]; } diff --git a/libswfdec/swfdec_root_movie.c b/libswfdec/swfdec_root_movie.c index 440f9d4..9121560 100644 --- a/libswfdec/swfdec_root_movie.c +++ b/libswfdec/swfdec_root_movie.c @@ -32,6 +32,7 @@ #include "swfdec_loadertarget.h" #include "swfdec_player_internal.h" #include "swfdec_swf_decoder.h" +#include "js/jsapi.h" static void swfdec_root_movie_loader_target_init (SwfdecLoaderTargetInterface *iface); @@ -67,6 +68,13 @@ swfdec_root_movie_loader_target_do_init swfdec_player_initialize (movie->player, movie->decoder->rate, movie->decoder->width, movie->decoder->height); + if (SWFDEC_IS_SWF_DECODER (movie->decoder) && + movie->player->roots->next == 0) { + /* if we're the only child */ + /* FIXME: check case sensitivity wrt embedding movies of different version */ + JS_SetContextCaseSensitive (movie->player->jscx, + SWFDEC_SWF_DECODER (movie->decoder)->version > 6); + } if (SWFDEC_IS_FLV_DECODER (movie->decoder)) { swfdec_flv_decoder_add_movie (SWFDEC_FLV_DECODER (movie->decoder), SWFDEC_MOVIE (movie)); diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 32af30e..e5c205f 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -315,8 +315,7 @@ swfdec_action_get_variable (JSContext *c s = swfdec_js_to_string (cx, cx->fp->sp[-1]); if (s == NULL) return JS_FALSE; - cx->fp->sp[-1] = swfdec_js_eval (cx, cx->fp->scopeChain, s, - ((SwfdecScript *) cx->fp->swf)->version < 7); + cx->fp->sp[-1] = swfdec_js_eval (cx, cx->fp->scopeChain, s); return JS_TRUE; } @@ -329,8 +328,7 @@ swfdec_action_set_variable (JSContext *c if (s == NULL) return JS_FALSE; - swfdec_js_eval_set (cx, cx->fp->scopeChain, s, cx->fp->sp[-1], - ((SwfdecScript *) cx->fp->swf)->version < 7); + swfdec_js_eval_set (cx, cx->fp->scopeChain, s, cx->fp->sp[-1]); cx->fp->sp -= 2; return JS_TRUE; } @@ -441,8 +439,7 @@ swfdec_eval_jsval (JSContext *cx, JSObje const char *bytes = swfdec_js_to_string (cx, *val); if (bytes == NULL) return JS_FALSE; - *val = swfdec_js_eval (cx, obj, bytes, - ((SwfdecScript *) cx->fp->swf)->version < 7); + *val = swfdec_js_eval (cx, obj, bytes); } else { *val = OBJECT_TO_JSVAL (obj); } @@ -458,7 +455,7 @@ swfdec_action_get_property (JSContext *c guint32 id; val = cx->fp->sp[-2]; - if (!swfdec_eval_jsval (cx, cx->fp->scopeChain, &val)) + if (!swfdec_eval_jsval (cx, NULL, &val)) return JS_FALSE; movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE); val = JSVAL_VOID; @@ -493,7 +490,7 @@ swfdec_action_set_property (JSContext *c guint32 id; val = cx->fp->sp[-3]; - if (!swfdec_eval_jsval (cx, cx->fp->scopeChain, &val)) + if (!swfdec_eval_jsval (cx, NULL, &val)) return JS_FALSE; movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE); if (movie == NULL) { diff-tree fc10e6599a2821de28900eb4f570654e4fe1958a (from 4db4a99c916781cbceb31ca171c242867d4047cd) Author: Benjamin Otte <otte@gnome.org> Date: Thu Jan 25 16:29:56 2007 +0100 That line must've been accidentally removed somewhere diff --git a/test/swfedit_token.c b/test/swfedit_token.c index 3327b81..8c8b075 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -112,6 +112,7 @@ swfedit_from_string_unsigned (const char return FALSE; if (u > max) return FALSE; + *result = GUINT_TO_POINTER (u); return TRUE; } diff-tree 4db4a99c916781cbceb31ca171c242867d4047cd (from 9dab0726ed4e35c06038b8700492bd62658ff689) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 21:37:13 2007 +0100 use swfdec_js_eval_set for SetVariable diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index b2c4c81..32af30e 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -329,11 +329,8 @@ swfdec_action_set_variable (JSContext *c if (s == NULL) return JS_FALSE; - if (strpbrk (s, "./:")) { - SWFDEC_WARNING ("FIXME: implement paths"); - } - if (!JS_SetProperty (cx, cx->fp->scopeChain, s, &cx->fp->sp[-1])) - return JS_FALSE; + swfdec_js_eval_set (cx, cx->fp->scopeChain, s, cx->fp->sp[-1], + ((SwfdecScript *) cx->fp->swf)->version < 7); cx->fp->sp -= 2; return JS_TRUE; } diff-tree 9dab0726ed4e35c06038b8700492bd62658ff689 (from 6d219aa23eb4010d5438fce453650c158d09a720) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 21:36:55 2007 +0100 implement swfdec_js_eval_set diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index bbd6a43..1601b4b 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -322,30 +322,38 @@ swfdec_js_eval_get_property (JSContext * } } -/** - * swfdec_js_eval: - * @cx: a #JSContext - * @obj: #JSObject to use as a source for evaluating - * @str: The string to evaluate - * @ignore_case: TRUE for case insensitive evaluation - * - * This function works like the Actionscript eval function used on @obj. - * It handles both slash-style and dot-style notation. - * - * Returns: the value or JSVAL_VOID if no value was found. - **/ -jsval -swfdec_js_eval (JSContext *cx, JSObject *obj, const char *str, - gboolean ignore_case) +static JSBool +swfdec_js_eval_set_property (JSContext *cx, JSObject *obj, + const char *name, gboolean initial, gboolean ignore_case, jsval *ret) +{ + JSAtom *atom; + JSObject *pobj; + JSProperty *prop; + + atom = js_Atomize (cx, name, strlen(name), ignore_case ? ATOM_NOCASE : 0); + if (!atom) + return JS_FALSE; + if (initial) { + return OBJ_SET_PROPERTY (cx, obj, (jsid) atom, ret); + } else { + if (!js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) + return JS_FALSE; + if (!prop) + return JS_FALSE; + if (pobj) + obj = pobj; + return OBJ_SET_PROPERTY (cx, obj, (jsid) prop->id, ret); + } +} + +static gboolean +swfdec_js_eval_internal (JSContext *cx, JSObject *obj, const char *str, + gboolean ignore_case, jsval *val, gboolean set) { jsval cur; char *work = NULL; gboolean initial = TRUE; - g_return_val_if_fail (cx != NULL, JSVAL_VOID); - g_return_val_if_fail (obj != NULL, JSVAL_VOID); - g_return_val_if_fail (str != NULL, JSVAL_VOID); - SWFDEC_LOG ("eval called with \"%s\" on %p", str, obj); if (strchr (str, '/')) { work = swfdec_js_slash_to_dot (str); @@ -369,19 +377,57 @@ swfdec_js_eval (JSContext *cx, JSObject g_free (name); str = dot + 1; } else { - if (!swfdec_js_eval_get_property (cx, obj, str, initial, ignore_case, &cur)) - goto out; + if (set) { + if (!swfdec_js_eval_set_property (cx, obj, str, initial, ignore_case, val)) + goto out; + } else { + if (!swfdec_js_eval_get_property (cx, obj, str, initial, ignore_case, &cur)) + goto out; + } str = NULL; } initial = FALSE; } g_free (work); - return cur; + *val = cur; + return TRUE; out: SWFDEC_DEBUG ("error: returning void for %s", str); g_free (work); - return JSVAL_VOID; + return FALSE; } +/** + * swfdec_js_eval: + * @cx: a #JSContext + * @obj: #JSObject to use as a source for evaluating + * @str: The string to evaluate + * @ignore_case: TRUE for case insensitive evaluation + * + * This function works like the Actionscript eval function used on @obj. + * It handles both slash-style and dot-style notation. + * + * Returns: the value or JSVAL_VOID if no value was found. + **/ +jsval +swfdec_js_eval (JSContext *cx, JSObject *obj, const char *str, + gboolean ignore_case) +{ + jsval ret; + + g_return_val_if_fail (cx != NULL, JSVAL_VOID); + g_return_val_if_fail (obj != NULL, JSVAL_VOID); + g_return_val_if_fail (str != NULL, JSVAL_VOID); + + if (!swfdec_js_eval_internal (cx, obj, str, ignore_case, &ret, FALSE)) + ret = JSVAL_VOID; + return ret; +} +void +swfdec_js_eval_set (JSContext *cx, JSObject *obj, const char *str, + jsval val, gboolean ignore_case) +{ + swfdec_js_eval_internal (cx, obj, str, ignore_case, &val, TRUE); +} diff --git a/libswfdec/swfdec_js.h b/libswfdec/swfdec_js.h index 47e97ff..ea49a72 100644 --- a/libswfdec/swfdec_js.h +++ b/libswfdec/swfdec_js.h @@ -51,6 +51,11 @@ jsval swfdec_js_eval (JSContext * cx JSObject * obj, const char * str, gboolean ignore_case); +void swfdec_js_eval_set (JSContext * cx, + JSObject * obj, + const char * str, + jsval val, + gboolean ignore_case); /* support functions */ const char * swfdec_js_to_string (JSContext * cx, diff-tree 6d219aa23eb4010d5438fce453650c158d09a720 (from 00501d98ab1ec0257887814ccc9d582b3b8113a3) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 18:44:35 2007 +0100 add support for colors and the SetBackground tag diff --git a/test/swfdec_out.c b/test/swfdec_out.c index b795b28..bf7aa9e 100644 --- a/test/swfdec_out.c +++ b/test/swfdec_out.c @@ -213,6 +213,7 @@ swfdec_out_put_rect (SwfdecOut *out, Swf guint req, tmp; g_return_if_fail (out != NULL); + g_return_if_fail (rect != NULL); x0 = rect->x0; y0 = rect->y0; @@ -233,3 +234,25 @@ swfdec_out_put_rect (SwfdecOut *out, Swf swfdec_out_put_sbits (out, y1, req); swfdec_out_syncbits (out); } + +void +swfdec_out_put_rgb (SwfdecOut *out, SwfdecColor color) +{ + g_return_if_fail (out != NULL); + + swfdec_out_put_u8 (out, SWF_COLOR_R (color)); + swfdec_out_put_u8 (out, SWF_COLOR_G (color)); + swfdec_out_put_u8 (out, SWF_COLOR_B (color)); +} + +void +swfdec_out_put_rgba (SwfdecOut *out, SwfdecColor color) +{ + g_return_if_fail (out != NULL); + + swfdec_out_put_u8 (out, SWF_COLOR_R (color)); + swfdec_out_put_u8 (out, SWF_COLOR_G (color)); + swfdec_out_put_u8 (out, SWF_COLOR_B (color)); + swfdec_out_put_u8 (out, SWF_COLOR_A (color)); +} + diff --git a/test/swfdec_out.h b/test/swfdec_out.h index b6d155f..d1f916c 100644 --- a/test/swfdec_out.h +++ b/test/swfdec_out.h @@ -21,6 +21,7 @@ #define __SWFDEC_OUT_H__ #include <libswfdec/swfdec_buffer.h> +#include <libswfdec/swfdec_color.h> #include <libswfdec/swfdec_rect.h> G_BEGIN_DECLS @@ -64,6 +65,10 @@ void swfdec_out_put_u16 (SwfdecOut * o void swfdec_out_put_u32 (SwfdecOut * out, guint i); +void swfdec_out_put_rgb (SwfdecOut * out, + SwfdecColor color); +void swfdec_out_put_rgba (SwfdecOut * out, + SwfdecColor color); void swfdec_out_put_rect (SwfdecOut * out, SwfdecRect * rect); diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c index 55020a0..dd15978 100644 --- a/test/swfedit_tag.c +++ b/test/swfedit_tag.c @@ -96,6 +96,30 @@ swfedit_rect_read (SwfdecBits *bits) return rect; } +static void +swfedit_rgb_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_rgb (out, GPOINTER_TO_UINT (data)); +} + +static gpointer +swfedit_rgb_read (SwfdecBits *bits) +{ + return GUINT_TO_POINTER (swfdec_bits_get_color (bits)); +} + +static void +swfedit_rgba_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_rgba (out, GPOINTER_TO_UINT (data)); +} + +static gpointer +swfedit_rgba_read (SwfdecBits *bits) +{ + return GUINT_TO_POINTER (swfdec_bits_get_rgba (bits)); +} + struct { void (* write) (gpointer data, SwfdecOut *out); gpointer (* read) (SwfdecBits *bits); @@ -106,6 +130,8 @@ struct { { swfedit_u16_write, swfedit_u16_read }, { swfedit_u32_write, swfedit_u32_read }, { swfedit_rect_write, swfedit_rect_read }, + { swfedit_rgb_write, swfedit_rgb_read }, + { swfedit_rgba_write, swfedit_rgba_read }, }; void @@ -156,14 +182,16 @@ swfedit_tag_read_token (SwfeditToken *to typedef struct { const char * name; /* name to use for this field */ SwfeditTokenType type; /* type of this field */ - guint n_items; /* field to look at for item count */ + guint n_items; /* field to look at for item count (or 0 to use 1 item) */ guint hint; /* hint to pass to field when creating */ } SwfeditTagDefinition; static const SwfeditTagDefinition ShowFrame[] = { { NULL, 0, 0, 0 } }; +static const SwfeditTagDefinition SetBackgroundColor[] = { { "color", SWFEDIT_TOKEN_RGB, 0, 0 }, { NULL, 0, 0, 0 } }; static const SwfeditTagDefinition *tags[] = { [SWFDEC_TAG_SHOWFRAME] = ShowFrame, + [SWFDEC_TAG_SETBACKGROUNDCOLOR] = SetBackgroundColor, }; static const SwfeditTagDefinition * diff --git a/test/swfedit_token.c b/test/swfedit_token.c index ecf471c..3327b81 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -22,42 +22,57 @@ #endif #include <stdlib.h> +#include <string.h> #include <gtk/gtk.h> #include <libswfdec/swfdec_buffer.h> +#include <libswfdec/swfdec_color.h> #include "swfedit_token.h" /*** CONVERTERS ***/ static gboolean +swfedit_parse_hex (const char *s, guint *result) +{ + guint byte; + + if (s[0] >= '0' && s[0] <= '9') + byte = s[0] - '0'; + else if (s[0] >= 'a' && s[0] <= 'f') + byte = s[0] + 10 - 'a'; + else if (s[0] >= 'A' && s[0] <= 'F') + byte = s[0] + 10 - 'A'; + else + return FALSE; + s++; + byte *= 16; + if (s[0] >= '0' && s[0] <= '9') + byte += s[0] - '0'; + else if (s[0] >= 'a' && s[0] <= 'f') + byte += s[0] + 10 - 'a'; + else if (s[0] >= 'A' && s[0] <= 'F') + byte += s[0] + 10 - 'A'; + else + return FALSE; + *result = byte; + return TRUE; +} + +static gboolean swfedit_binary_from_string (const char *s, gpointer* result) { GByteArray *array = g_byte_array_new (); - guint8 byte; + guint byte; + guint8 add; while (g_ascii_isspace (*s)) s++; do { - if (s[0] >= '0' && s[0] <= '9') - byte = s[0] - '0'; - else if (s[0] >= 'a' && s[0] <= 'f') - byte = s[0] + 10 - 'a'; - else if (s[0] >= 'A' && s[0] <= 'F') - byte = s[0] + 10 - 'A'; - else + if (!swfedit_parse_hex (s, &byte)) break; - s++; - byte *= 16; - if (s[0] >= '0' && s[0] <= '9') - byte += s[0] - '0'; - else if (s[0] >= 'a' && s[0] <= 'f') - byte += s[0] + 10 - 'a'; - else if (s[0] >= 'A' && s[0] <= 'F') - byte += s[0] + 10 - 'A'; - else - break; - s++; - g_byte_array_append (array, &byte, 1); + s += 2; + add = byte; + g_byte_array_append (array, &add, 1); while (g_ascii_isspace (*s)) s++; - } while (TRUE); + } while (*s != '\0'); if (*s == '\0') { SwfdecBuffer *buffer = swfdec_buffer_new (); buffer->length = array->len; @@ -97,7 +112,6 @@ swfedit_from_string_unsigned (const char return FALSE; if (u > max) return FALSE; - *result = GUINT_TO_POINTER ((guint) u); return TRUE; } @@ -140,6 +154,63 @@ swfedit_rect_to_string (gconstpointer va (int) rect->x1, (int) rect->y1); } +static gboolean +swfedit_rgb_from_string (const char *s, gpointer* result) +{ + guint r, g, b; + if (strlen (s) != 6) + return FALSE; + if (!swfedit_parse_hex (s, &r)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &g)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &b)) + return FALSE; + *result = GUINT_TO_POINTER (SWF_COLOR_COMBINE (r, g, b, 0xFF)); + return TRUE; +} + +static char * +swfedit_rgb_to_string (gconstpointer value) +{ + guint c = GPOINTER_TO_UINT (value); + + return g_strdup_printf ("%02X%02X%02X", SWF_COLOR_R (c), + SWF_COLOR_G (c), SWF_COLOR_B (c)); +} + +static gboolean +swfedit_rgba_from_string (const char *s, gpointer* result) +{ + guint r, g, b, a; + if (strlen (s) != 8) + return FALSE; + if (!swfedit_parse_hex (s, &a)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &r)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &g)) + return FALSE; + s += 2; + if (!swfedit_parse_hex (s, &b)) + return FALSE; + *result = GUINT_TO_POINTER (SWF_COLOR_COMBINE (r, g, b, a)); + return TRUE; +} + +static char * +swfedit_rgba_to_string (gconstpointer value) +{ + guint c = GPOINTER_TO_UINT (value); + + return g_strdup_printf ("%02X%02X%02X%02X", SWF_COLOR_R (c), + SWF_COLOR_G (c), SWF_COLOR_B (c), SWF_COLOR_A (c)); +} + struct { gboolean (* from_string) (const char *s, gpointer *); char * (* to_string) (gconstpointer value); @@ -151,6 +222,8 @@ struct { { swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL }, { swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL }, { swfedit_rect_from_string, swfedit_rect_to_string, g_free }, + { swfedit_rgb_from_string, swfedit_rgb_to_string, NULL }, + { swfedit_rgba_from_string, swfedit_rgba_to_string, NULL }, }; /*** GTK_TREE_MODEL ***/ diff --git a/test/swfedit_token.h b/test/swfedit_token.h index 8dec753..7909188 100644 --- a/test/swfedit_token.h +++ b/test/swfedit_token.h @@ -32,6 +32,8 @@ typedef enum { SWFEDIT_TOKEN_UINT16, SWFEDIT_TOKEN_UINT32, SWFEDIT_TOKEN_RECT, + SWFEDIT_TOKEN_RGB, + SWFEDIT_TOKEN_RGBA, SWFEDIT_N_TOKENS } SwfeditTokenType; diff-tree 00501d98ab1ec0257887814ccc9d582b3b8113a3 (from e0270bcea5766d30ae6eeb7f8b0f0ef062f121f4) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 18:44:11 2007 +0100 implement StringAdd and GetURL, so Steve dances again diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 171877f..b2c4c81 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -773,9 +773,62 @@ swfdec_action_increment (JSContext *cx, return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); } +static JSBool +swfdec_action_get_url (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie; + SwfdecBits bits; + const char *url, *target; + + swfdec_bits_init_data (&bits, data, len); + url = swfdec_bits_skip_string (&bits); + target = swfdec_bits_skip_string (&bits); + if (swfdec_bits_left (&bits)) { + SWFDEC_WARNING ("leftover bytes in GetURL action"); + } + movie = swfdec_action_get_target (cx); + if (movie) + swfdec_root_movie_load (SWFDEC_ROOT_MOVIE (movie->root), url, target); + else + SWFDEC_WARNING ("no movie to load"); + return JS_TRUE; +} + +static JSBool +swfdec_action_string_add (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSString *lval, *rval; + + rval = JS_ValueToString (cx, cx->fp->sp[-1]); + lval = JS_ValueToString (cx, cx->fp->sp[-2]); + if (lval == NULL || rval == NULL) + return FALSE; + lval = JS_ConcatStrings (cx, lval, rval); + if (lval == NULL) + return FALSE; + cx->fp->sp--; + cx->fp->sp[-1] = STRING_TO_JSVAL (lval); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_get_url (guint action, const guint8 *data, guint len) +{ + SwfdecBits bits; + const char *url, *target; + + swfdec_bits_init_data (&bits, data, len); + url = swfdec_bits_skip_string (&bits); + target = swfdec_bits_skip_string (&bits); + if (swfdec_bits_left (&bits)) { + SWFDEC_WARNING ("leftover bytes in GetURL action"); + } + return g_strdup_printf ("GetURL %s %s", url, target); +} + +static char * swfdec_action_print_if (guint action, const guint8 *data, guint len) { if (len != 2) { @@ -942,7 +995,7 @@ static const SwfdecActionSpec actions[25 [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } }, [0x20] = { "SetTarget2", NULL }, - [0x21] = { "StringAdd", NULL }, + [0x21] = { "StringAdd", NULL, 2, 1, { NULL, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add } }, [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } }, [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } }, [0x24] = { "CloneSprite", NULL }, @@ -1010,7 +1063,7 @@ static const SwfdecActionSpec actions[25 /* version 3 */ [0x81] = { "GotoFrame", swfdec_action_print_goto_frame, 0, 0, { swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame } }, - [0x83] = { "GetURL", NULL }, + [0x83] = { "GetURL", swfdec_action_print_get_url, 0, 0, { swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url } }, /* version 5 */ [0x87] = { "StoreRegister", NULL }, [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } }, diff-tree e0270bcea5766d30ae6eeb7f8b0f0ef062f121f4 (from 6efabb680e16b9144d8b4e880c18396861190d69) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 18:43:48 2007 +0100 make the color functions return a SwfdecColor diff --git a/libswfdec/swfdec_bits.c b/libswfdec/swfdec_bits.c index 1a7e402..418e9eb 100644 --- a/libswfdec/swfdec_bits.c +++ b/libswfdec/swfdec_bits.c @@ -471,10 +471,10 @@ swfdec_bits_get_string_length (SwfdecBit return ret; } -unsigned int +SwfdecColor swfdec_bits_get_color (SwfdecBits * bits) { - int r, g, b; + unsigned int r, g, b; r = swfdec_bits_get_u8 (bits); g = swfdec_bits_get_u8 (bits); @@ -483,10 +483,10 @@ swfdec_bits_get_color (SwfdecBits * bits return SWF_COLOR_COMBINE (r, g, b, 0xff); } -unsigned int +SwfdecColor swfdec_bits_get_rgba (SwfdecBits * bits) { - int r, g, b, a; + unsigned int r, g, b, a; r = swfdec_bits_get_u8 (bits); g = swfdec_bits_get_u8 (bits); diff --git a/libswfdec/swfdec_bits.h b/libswfdec/swfdec_bits.h index 08ae1d8..a44c9e2 100644 --- a/libswfdec/swfdec_bits.h +++ b/libswfdec/swfdec_bits.h @@ -65,8 +65,8 @@ const char *swfdec_bits_skip_string (Swf guint swfdec_bits_skip_bytes (SwfdecBits *bits, guint bytes); char *swfdec_bits_get_string (SwfdecBits * bits); char *swfdec_bits_get_string_length (SwfdecBits * bits, unsigned int len); -unsigned int swfdec_bits_get_color (SwfdecBits * bits); -unsigned int swfdec_bits_get_rgba (SwfdecBits * bits); +SwfdecColor swfdec_bits_get_color (SwfdecBits * bits); +SwfdecColor swfdec_bits_get_rgba (SwfdecBits * bits); SwfdecGradient *swfdec_bits_get_gradient (SwfdecBits * bits); SwfdecGradient *swfdec_bits_get_gradient_rgba (SwfdecBits * bits); SwfdecGradient *swfdec_bits_get_morph_gradient (SwfdecBits * bits); diff-tree 6efabb680e16b9144d8b4e880c18396861190d69 (from f1207b1451c4061e86adf62637134d63909ab754) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 16:40:58 2007 +0100 add initial support for auto-extraction of contents diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c index 0a9fb9b..55020a0 100644 --- a/test/swfedit_tag.c +++ b/test/swfedit_tag.c @@ -25,6 +25,7 @@ #include <gtk/gtk.h> #include <libswfdec/swfdec_bits.h> +#include <libswfdec/swfdec_tag.h> #include "swfedit_tag.h" #include "swfdec_out.h" @@ -150,6 +151,29 @@ swfedit_tag_read_token (SwfeditToken *to swfedit_token_add (token, name, type, data); } +/*** TAGS ***/ + +typedef struct { + const char * name; /* name to use for this field */ + SwfeditTokenType type; /* type of this field */ + guint n_items; /* field to look at for item count */ + guint hint; /* hint to pass to field when creating */ +} SwfeditTagDefinition; + +static const SwfeditTagDefinition ShowFrame[] = { { NULL, 0, 0, 0 } }; + +static const SwfeditTagDefinition *tags[] = { + [SWFDEC_TAG_SHOWFRAME] = ShowFrame, +}; + +static const SwfeditTagDefinition * +swfedit_tag_get_definition (guint tag) +{ + if (tag >= G_N_ELEMENTS (tags)) + return NULL; + return tags[tag]; +} + /*** SWFEDIT_TAG ***/ G_DEFINE_TYPE (SwfeditTag, swfedit_tag, SWFEDIT_TYPE_TOKEN) @@ -179,13 +203,23 @@ SwfeditTag * swfedit_tag_new (SwfeditToken *parent, guint tag, SwfdecBuffer *buffer) { SwfeditTag *item; + const SwfeditTagDefinition *def; g_return_val_if_fail (SWFEDIT_IS_TOKEN (parent), NULL); item = g_object_new (SWFEDIT_TYPE_TAG, NULL); item->tag = tag; SWFEDIT_TOKEN (item)->parent = parent; - swfedit_token_add (SWFEDIT_TOKEN (item), "contents", SWFEDIT_TOKEN_BINARY, buffer); + def = swfedit_tag_get_definition (tag); + if (def) { + SwfdecBits bits; + swfdec_bits_init (&bits, buffer); + for (;def->name != NULL; def++) { + swfedit_tag_read_token (SWFEDIT_TOKEN (item), &bits, def->name, def->type); + } + } else { + swfedit_token_add (SWFEDIT_TOKEN (item), "contents", SWFEDIT_TOKEN_BINARY, buffer); + } return item; } diff-tree f1207b1451c4061e86adf62637134d63909ab754 (from 2699f0ac28fe220c12fe6f98b05c50937125aeea) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 16:40:35 2007 +0100 handle tokens without children diff --git a/test/swfedit_token.c b/test/swfedit_token.c index b2210fd..ecf471c 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -309,6 +309,8 @@ swfedit_token_iter_children (GtkTreeMode } else { token = SWFEDIT_TOKEN (tree_model); } + if (token->tokens->len == 0) + return FALSE; iter->stamp = 0; /* FIXME */ iter->user_data = token; iter->user_data2 = GINT_TO_POINTER (0); @@ -322,7 +324,7 @@ swfedit_token_iter_has_child (GtkTreeMod SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); REPORT; - return entry->type == SWFEDIT_TOKEN_OBJECT; + return entry->type == SWFEDIT_TOKEN_OBJECT && SWFEDIT_TOKEN (entry->value)->tokens->len > 0; } static gint @@ -333,7 +335,7 @@ swfedit_token_iter_n_children (GtkTreeMo REPORT; if (entry->type != SWFEDIT_TOKEN_OBJECT) - return FALSE; + return 0; token = entry->value; return token->tokens->len; diff-tree 2699f0ac28fe220c12fe6f98b05c50937125aeea (from 4d09855e83ee699d590e8916e4af318ab79cc99b) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 15:44:38 2007 +0100 remove debugging g_print diff --git a/test/swfdec_out.c b/test/swfdec_out.c index 70dcc7c..b795b28 100644 --- a/test/swfdec_out.c +++ b/test/swfdec_out.c @@ -168,7 +168,6 @@ swfdec_out_put_bits (SwfdecOut *out, gui *out->ptr = 0; value &= (1 << bits_now) - 1; value <<= 8 - out->idx - bits_now; - g_print ("putting %02X in the next %u bits\n", value, bits_now); *out->ptr |= value; out->idx += bits_now; g_assert (out->idx <= 8); diff-tree 4d09855e83ee699d590e8916e4af318ab79cc99b (from 82e3f5645e07b82da355444ae96ccbb6eba637dd) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 15:14:12 2007 +0100 implement saving diff --git a/test/Makefile.am b/test/Makefile.am index d168cfd..33a647c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -19,12 +19,14 @@ swfedit_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_ swfedit_LDFLAGS = $(SWF_LIBS) $(GTK_LIBS) swfedit_SOURCES = \ + swfdec_out.c \ swfedit.c \ swfedit_file.c \ swfedit_tag.c \ swfedit_token.c noinst_HEADERS = \ + swfdec_out.h \ swfedit_file.h \ swfedit_tag.h \ swfedit_token.h diff --git a/test/swfdec_out.c b/test/swfdec_out.c new file mode 100644 index 0000000..70dcc7c --- /dev/null +++ b/test/swfdec_out.c @@ -0,0 +1,236 @@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "swfdec_out.h" + +SwfdecOut * +swfdec_out_open (void) +{ + SwfdecOut *out = g_new0 (SwfdecOut, 1); + + out->data = g_malloc (SWFDEC_OUT_INITIAL); + out->ptr = out->data; + out->end = out->data + SWFDEC_OUT_INITIAL; + + return out; +} + +static void +swfdec_out_syncbits (SwfdecOut *out) +{ + g_return_if_fail (out != NULL); + + if (out->idx > 0) { + out->ptr++; + out->idx = 0; + } +} + +SwfdecBuffer * +swfdec_out_close (SwfdecOut *out) +{ + SwfdecBuffer *buffer; + + g_return_val_if_fail (out != NULL, NULL); + + swfdec_out_syncbits (out); + + buffer = swfdec_buffer_new (); + buffer->data = out->data; + buffer->length = out->ptr - out->data; + + g_free (out); + + return buffer; +} + +unsigned int +swfdec_out_left (SwfdecOut *out) +{ + g_return_val_if_fail (out != NULL, 0); + + return (out->end - out->ptr) * 8 - out->idx; +} + +void +swfdec_out_ensure_bits (SwfdecOut *out, unsigned int bits) +{ + unsigned int current, taken, needed; + + g_return_if_fail (out != NULL); + + current = swfdec_out_left (out); + if (current >= bits) + return; + taken = out->ptr - out->data; + needed = (bits - current + 7) / 8; + needed += SWFDEC_OUT_STEP; + needed -= needed % SWFDEC_OUT_STEP; + needed += out->end - out->data; + out->data = g_realloc (out->data, needed); + out->ptr = out->data + taken; + out->end = out->data + needed; +} + +void +swfdec_out_prepare_bytes (SwfdecOut *out, unsigned int bytes) +{ + g_return_if_fail (out != NULL); + + swfdec_out_syncbits (out); + swfdec_out_ensure_bits (out, bytes * 8); +} + +void +swfdec_out_put_buffer (SwfdecOut *out, SwfdecBuffer *buffer) +{ + g_return_if_fail (out != NULL); + + swfdec_out_prepare_bytes (out, buffer->length); + memcpy (out->ptr, buffer->data, buffer->length); + out->ptr += buffer->length; +} + +void +swfdec_out_put_u8 (SwfdecOut *out, guint i) +{ + g_return_if_fail (i <= G_MAXUINT8); + + swfdec_out_prepare_bytes (out, 1); + *out->ptr = i; + out->ptr++; +} + +void +swfdec_out_put_u16 (SwfdecOut *out, guint i) +{ + g_return_if_fail (i <= G_MAXUINT16); + + swfdec_out_prepare_bytes (out, 2); + *(guint16 *)out->ptr = GUINT16_TO_LE (i); + out->ptr += 2; +} + +void +swfdec_out_put_u32 (SwfdecOut *out, guint i) +{ + g_return_if_fail (i <= G_MAXUINT32); + + swfdec_out_prepare_bytes (out, 4); + *(guint32 *)out->ptr = GUINT32_TO_LE (i); + out->ptr += 4; +} + +void +swfdec_out_put_bit (SwfdecOut *out, gboolean bit) +{ + g_return_if_fail (out != NULL); + + swfdec_out_put_bits (out, bit ? 1 : 0, 1); +} + +void +swfdec_out_put_bits (SwfdecOut *out, guint bits, guint n_bits) +{ + g_return_if_fail (out != NULL); + + swfdec_out_ensure_bits (out, n_bits); + + /* FIXME: implement this less braindead */ + while (n_bits) { + guint bits_now = MIN (n_bits, 8 - out->idx); + guint value = bits >> (n_bits - bits_now); + + /* clear data if necessary */ + if (out->idx == 0) + *out->ptr = 0; + value &= (1 << bits_now) - 1; + value <<= 8 - out->idx - bits_now; + g_print ("putting %02X in the next %u bits\n", value, bits_now); + *out->ptr |= value; + out->idx += bits_now; + g_assert (out->idx <= 8); + if (out->idx == 8) { + out->ptr ++; + out->idx = 0; + } + n_bits -= bits_now; + } +} + +void +swfdec_out_put_sbits (SwfdecOut *out, int bits, guint n_bits) +{ + g_return_if_fail (out != NULL); + swfdec_out_put_bits (out, bits, n_bits); +} + +static guint +swfdec_out_bits_required (guint x) +{ + guint ret = 0; + + while (x > 0) { + x >>= 1; + ret++; + } + return ret; +} + +static guint +swfdec_out_sbits_required (int x) +{ + if (x < 0) + x = -x; + return swfdec_out_bits_required (x) + 1; +} + +void +swfdec_out_put_rect (SwfdecOut *out, SwfdecRect *rect) +{ + int x0, x1, y0, y1; + guint req, tmp; + + g_return_if_fail (out != NULL); + + x0 = rect->x0; + y0 = rect->y0; + x1 = rect->x1; + y1 = rect->y1; + req = swfdec_out_sbits_required (x0); + tmp = swfdec_out_sbits_required (y0); + req = MAX (req, tmp); + tmp = swfdec_out_sbits_required (x1); + req = MAX (req, tmp); + tmp = swfdec_out_sbits_required (y1); + req = MAX (req, tmp); + swfdec_out_syncbits (out); + swfdec_out_put_bits (out, req, 5); + swfdec_out_put_sbits (out, x0, req); + swfdec_out_put_sbits (out, x1, req); + swfdec_out_put_sbits (out, y0, req); + swfdec_out_put_sbits (out, y1, req); + swfdec_out_syncbits (out); +} diff --git a/test/swfdec_out.h b/test/swfdec_out.h new file mode 100644 index 0000000..b6d155f --- /dev/null +++ b/test/swfdec_out.h @@ -0,0 +1,73 @@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __SWFDEC_OUT_H__ +#define __SWFDEC_OUT_H__ + +#include <libswfdec/swfdec_buffer.h> +#include <libswfdec/swfdec_rect.h> + +G_BEGIN_DECLS + + +typedef struct _SwfdecOut SwfdecOut; + +struct _SwfdecOut { + unsigned char * data; + unsigned char * ptr; + unsigned int idx; + unsigned char * end; +}; + +#define SWFDEC_OUT_INITIAL (32) +#define SWFDEC_OUT_STEP (32) + +SwfdecOut * swfdec_out_open (void); +SwfdecBuffer * swfdec_out_close (SwfdecOut * out); + +unsigned int swfdec_out_left (SwfdecOut * out); +void swfdec_out_ensure_bits (SwfdecOut * out, + unsigned int bits); +void swfdec_out_prepare_bytes (SwfdecOut * out, + unsigned int bytes); + +void swfdec_out_put_bit (SwfdecOut * out, + gboolean bit); +void swfdec_out_put_bits (SwfdecOut * out, + guint bits, + guint n_bits); +void swfdec_out_put_sbits (SwfdecOut * out, + int bits, + guint n_bits); +void swfdec_out_put_buffer (SwfdecOut * out, + SwfdecBuffer * buffer); +void swfdec_out_put_u8 (SwfdecOut * out, + guint i); +void swfdec_out_put_u16 (SwfdecOut * out, + guint i); +void swfdec_out_put_u32 (SwfdecOut * out, + guint i); + +void swfdec_out_put_rect (SwfdecOut * out, + SwfdecRect * rect); + + +G_END_DECLS + +#endif diff --git a/test/swfedit.c b/test/swfedit.c index e16d645..258f25e 100644 --- a/test/swfedit.c +++ b/test/swfedit.c @@ -27,12 +27,26 @@ static void save (GtkButton *button, SwfeditFile *file) { + GtkWidget *dialog; GError *error = NULL; - if (!swfedit_file_save (file, &error)) { - g_printerr ("Error saving fils: %s\n", error->message); - g_error_free (error); + dialog = gtk_file_chooser_dialog_new ("Save file...", + GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_OK, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), file->filename); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { + g_free (file->filename); + file->filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + if (!swfedit_file_save (file, &error)) { + g_printerr ("Error saving file: %s\n", error->message); + g_error_free (error); + } } + gtk_widget_destroy (dialog); } static void diff --git a/test/swfedit_file.c b/test/swfedit_file.c index d660655..dd5e035 100644 --- a/test/swfedit_file.c +++ b/test/swfedit_file.c @@ -27,6 +27,7 @@ #include "libswfdec/swfdec_buffer.h" #include "libswfdec/swfdec_debug.h" #include "libswfdec/swfdec_swf_decoder.h" +#include "swfdec_out.h" #include "swfedit_file.h" #include "swfedit_tag.h" @@ -103,7 +104,7 @@ swf_parse_header1 (SwfeditFile *file, Sw swfedit_token_add (SWFEDIT_TOKEN (file), "version", SWFEDIT_TOKEN_UINT8, GUINT_TO_POINTER (swfdec_bits_get_u8 (bits))); - bytes_total = swfdec_bits_get_u32 (bits); + bytes_total = swfdec_bits_get_u32 (bits) - 8; if (sig1 == 'C') { /* compressed */ @@ -113,7 +114,7 @@ swf_parse_header1 (SwfeditFile *file, Sw "Unable to uncompress file"); return ret; } else { - SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, -1); + SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, bytes_total); if (ret == NULL) g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "File too small"); @@ -124,14 +125,9 @@ swf_parse_header1 (SwfeditFile *file, Sw static void swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits) { - SwfdecRect rect; - - swfdec_bits_get_rect (bits, &rect); - swfdec_bits_syncbits (bits); - swfedit_token_add (SWFEDIT_TOKEN (file), "rate", SWFEDIT_TOKEN_UINT16, - GUINT_TO_POINTER (swfdec_bits_get_u16 (bits))); - swfedit_token_add (SWFEDIT_TOKEN (file), "frames", SWFEDIT_TOKEN_UINT16, - GUINT_TO_POINTER (swfdec_bits_get_u16 (bits))); + swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rect", SWFEDIT_TOKEN_RECT); + swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rate", SWFEDIT_TOKEN_UINT16); + swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "frames", SWFEDIT_TOKEN_UINT16); } static gboolean @@ -193,13 +189,21 @@ swfedit_file_new (const char *filename, SwfeditFile *file; SwfdecBuffer *buffer; SwfdecBits bits; + char *absolute; + if (g_path_is_absolute (filename)) { + absolute = g_strdup (filename); + } else { + char *dir = g_get_current_dir (); + absolute = g_build_filename (dir, filename, NULL); + g_free (dir); + } buffer = swfdec_buffer_new_from_file (filename, error); if (buffer == NULL) return NULL; swfdec_bits_init (&bits, buffer); file = g_object_new (SWFEDIT_TYPE_FILE, NULL); - file->filename = g_strdup (filename); + file->filename = absolute; if (!swfedit_file_parse (file, &bits, error)) { swfdec_buffer_unref (buffer); g_object_unref (file); @@ -212,7 +216,53 @@ swfedit_file_new (const char *filename, static SwfdecBuffer * swfedit_file_write (SwfeditFile *file) { - return NULL; + guint i; + SwfeditToken *token = SWFEDIT_TOKEN (file); + SwfdecBufferQueue *queue; + SwfdecBuffer *buffer; + SwfdecOut *out; + + queue = swfdec_buffer_queue_new (); + /* write second part of header */ + out = swfdec_out_open (); + swfedit_tag_write_token (token, out, 1); + swfedit_tag_write_token (token, out, 2); + swfedit_tag_write_token (token, out, 3); + swfdec_buffer_queue_push (queue, swfdec_out_close (out)); + + for (i = 4; i < token->tokens->len; i++) { + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); + g_assert (entry->type == SWFEDIT_TOKEN_OBJECT); + + buffer = swfedit_tag_write (entry->value); + out = swfdec_out_open (); + swfdec_out_put_u16 (out, SWFEDIT_TAG (entry->value)->tag << 6 | + MIN (buffer->length, 0x3f)); + if (buffer->length >= 0x3f) { + swfdec_out_put_u32 (out, buffer->length); + } + swfdec_buffer_queue_push (queue, swfdec_out_close (out)); + swfdec_buffer_queue_push (queue, buffer); + } + /* write closing tag */ + buffer = swfdec_buffer_new_and_alloc0 (2); + swfdec_buffer_queue_push (queue, buffer); + + /* FIXME: implement compression */ + out = swfdec_out_open (); + swfdec_out_put_u8 (out, 'F'); + swfdec_out_put_u8 (out, 'W'); + swfdec_out_put_u8 (out, 'S'); + swfedit_tag_write_token (token, out, 0); + g_print ("length: %u", swfdec_buffer_queue_get_depth (queue)); + swfdec_out_put_u32 (out, swfdec_buffer_queue_get_depth (queue) + 8); + swfdec_out_prepare_bytes (out, swfdec_buffer_queue_get_depth (queue)); + while ((buffer = swfdec_buffer_queue_pull_buffer (queue))) { + swfdec_out_put_buffer (out, buffer); + swfdec_buffer_unref (buffer); + } + swfdec_buffer_queue_free (queue); + return swfdec_out_close (out); } gboolean diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c index 94ac4f9..0a9fb9b 100644 --- a/test/swfedit_tag.c +++ b/test/swfedit_tag.c @@ -23,7 +23,134 @@ #include <stdlib.h> #include <gtk/gtk.h> + +#include <libswfdec/swfdec_bits.h> #include "swfedit_tag.h" +#include "swfdec_out.h" + +/*** LOAD/SAVE ***/ + +static void +swfedit_binary_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_buffer (out, data); +} + +static gpointer +swfedit_binary_read (SwfdecBits *bits) +{ + SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, -1); + if (buffer == NULL) + buffer = swfdec_buffer_new (); + return buffer; +} + +static void +swfedit_u8_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_u8 (out, GPOINTER_TO_UINT (data)); +} + +static gpointer +swfedit_u8_read (SwfdecBits *bits) +{ + return GUINT_TO_POINTER (swfdec_bits_get_u8 (bits)); +} + +static void +swfedit_u16_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_u16 (out, GPOINTER_TO_UINT (data)); +} + +static gpointer +swfedit_u16_read (SwfdecBits *bits) +{ + return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits)); +} + +static void +swfedit_u32_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_u32 (out, GPOINTER_TO_UINT (data)); +} + +static gpointer +swfedit_u32_read (SwfdecBits *bits) +{ + return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits)); +} + +static void +swfedit_rect_write (gpointer data, SwfdecOut *out) +{ + swfdec_out_put_rect (out, data); +} + +static gpointer +swfedit_rect_read (SwfdecBits *bits) +{ + SwfdecRect *rect = g_new (SwfdecRect, 1); + swfdec_bits_get_rect (bits, rect); + return rect; +} + +struct { + void (* write) (gpointer data, SwfdecOut *out); + gpointer (* read) (SwfdecBits *bits); +} operations[SWFEDIT_N_TOKENS] = { + { NULL, NULL }, + { swfedit_binary_write, swfedit_binary_read }, + { swfedit_u8_write, swfedit_u8_read }, + { swfedit_u16_write, swfedit_u16_read }, + { swfedit_u32_write, swfedit_u32_read }, + { swfedit_rect_write, swfedit_rect_read }, +}; + +void +swfedit_tag_write_token (SwfeditToken *token, SwfdecOut *out, guint i) +{ + SwfeditTokenEntry *entry; + + g_return_if_fail (SWFEDIT_IS_TOKEN (token)); + g_return_if_fail (i < token->tokens->len); + + entry = &g_array_index (token->tokens, + SwfeditTokenEntry, i); + g_assert (operations[entry->type].write != NULL); + operations[entry->type].write (entry->value, out); +} + +SwfdecBuffer * +swfedit_tag_write (SwfeditTag *tag) +{ + guint i; + SwfdecOut *out; + + g_return_val_if_fail (SWFEDIT_IS_TAG (tag), NULL); + + out = swfdec_out_open (); + for (i = 0; i < SWFEDIT_TOKEN (tag)->tokens->len; i++) { + swfedit_tag_write_token (SWFEDIT_TOKEN (tag), out, i); + } + return swfdec_out_close (out); +} + +void +swfedit_tag_read_token (SwfeditToken *token, SwfdecBits *bits, + const char *name, SwfeditTokenType type) +{ + gpointer data; + + g_return_if_fail (SWFEDIT_IS_TOKEN (token)); + g_return_if_fail (name != NULL); + + g_assert (operations[type].read != NULL); + data = operations[type].read (bits); + swfedit_token_add (token, name, type, data); +} + +/*** SWFEDIT_TAG ***/ G_DEFINE_TYPE (SwfeditTag, swfedit_tag, SWFEDIT_TYPE_TOKEN) diff --git a/test/swfedit_tag.h b/test/swfedit_tag.h index 07c11f2..46fdb5f 100644 --- a/test/swfedit_tag.h +++ b/test/swfedit_tag.h @@ -21,6 +21,7 @@ #define __SWFEDIT_TAG_H__ #include <libswfdec/swfdec_buffer.h> +#include "swfdec_out.h" #include "swfedit_token.h" G_BEGIN_DECLS @@ -47,10 +48,18 @@ struct _SwfeditTagClass { GType swfedit_tag_get_type (void); -SwfeditTag * swfedit_tag_new (SwfeditToken * parent, - guint tag, - SwfdecBuffer * buffer); - +SwfeditTag * swfedit_tag_new (SwfeditToken * parent, + guint tag, + SwfdecBuffer * buffer); + +SwfdecBuffer * swfedit_tag_write (SwfeditTag * tag); +void swfedit_tag_write_token (SwfeditToken * token, + SwfdecOut * out, + guint i); +void swfedit_tag_read_token (SwfeditToken * token, + SwfdecBits * bits, + const char * name, + SwfeditTokenType type); G_END_DECLS diff --git a/test/swfedit_token.c b/test/swfedit_token.c index f3623fc..b2210fd 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -125,6 +125,21 @@ swfedit_to_string_unsigned (gconstpointe return g_strdup_printf ("%u", GPOINTER_TO_UINT (value)); } +static gboolean +swfedit_rect_from_string (const char *s, gpointer* result) +{ + return FALSE; +} + +static char * +swfedit_rect_to_string (gconstpointer value) +{ + const SwfdecRect *rect = value; + + return g_strdup_printf ("%d, %d, %d, %d", (int) rect->x0, (int) rect->y0, + (int) rect->x1, (int) rect->y1); +} + struct { gboolean (* from_string) (const char *s, gpointer *); char * (* to_string) (gconstpointer value); @@ -135,6 +150,7 @@ struct { { swfedit_uint8_from_string, swfedit_to_string_unsigned, NULL }, { swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL }, { swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL }, + { swfedit_rect_from_string, swfedit_rect_to_string, g_free }, }; /*** GTK_TREE_MODEL ***/ diff --git a/test/swfedit_token.h b/test/swfedit_token.h index 5235d03..8dec753 100644 --- a/test/swfedit_token.h +++ b/test/swfedit_token.h @@ -31,6 +31,7 @@ typedef enum { SWFEDIT_TOKEN_UINT8, SWFEDIT_TOKEN_UINT16, SWFEDIT_TOKEN_UINT32, + SWFEDIT_TOKEN_RECT, SWFEDIT_N_TOKENS } SwfeditTokenType; diff-tree 82e3f5645e07b82da355444ae96ccbb6eba637dd (from 89df12bea205242dd0554a48a0e7721de67d531b) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 15:13:58 2007 +0100 add swfedit diff --git a/test/.gitignore b/test/.gitignore index ef52ce4..9280a20 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -11,3 +11,4 @@ Makefile.in dump parse swfdec-extract +swfedit diff-tree 89df12bea205242dd0554a48a0e7721de67d531b (from 91403c6d7fbda752ba3403e676d679afdb2bf1b0) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 15:11:05 2007 +0100 We need at least gtk-2.8 diff --git a/configure.ac b/configure.ac index eb69535..fbf58c3 100644 --- a/configure.ac +++ b/configure.ac @@ -78,7 +78,7 @@ fi AC_SUBST(PANGO_LIBS) AC_SUBST(PANGO_CFLAGS) -PKG_CHECK_MODULES(GTK, gtk+-2.0, HAVE_GTK=yes, HAVE_GTK=no) +PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.8.0, HAVE_GTK=yes, HAVE_GTK=no) AC_SUBST(GTK_LIBS) AC_SUBST(GTK_CFLAGS) if test "$HAVE_GTK" = "no"; then diff-tree 91403c6d7fbda752ba3403e676d679afdb2bf1b0 (from 800b8b573d0d3553336f8541163a4731888bfbbb) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 15:10:35 2007 +0100 we don't have the header in the uncompressed buffer diff --git a/libswfdec/swfdec_swf_decoder.c b/libswfdec/swfdec_swf_decoder.c index 6539921..0bc1099 100644 --- a/libswfdec/swfdec_swf_decoder.c +++ b/libswfdec/swfdec_swf_decoder.c @@ -143,7 +143,7 @@ swf_inflate_init (SwfdecSwfDecoder * s) ret = inflateInit (z); SWFDEC_DEBUG ("inflateInit returned %d", ret); - s->uncompressed_buffer = swfdec_buffer_new_and_alloc (dec->bytes_total); + s->uncompressed_buffer = swfdec_buffer_new_and_alloc (dec->bytes_total - 8); z->next_out = s->uncompressed_buffer->data; z->avail_out = s->uncompressed_buffer->length; z->opaque = NULL; diff-tree 800b8b573d0d3553336f8541163a4731888bfbbb (from b32e8c5b76f4dfde34c72057feb9d9970bea2e7a) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 24 15:10:04 2007 +0100 ignore 0-length buffers in bufferqueue diff --git a/libswfdec/swfdec_buffer.c b/libswfdec/swfdec_buffer.c index 3e9af24..c4ac67e 100644 --- a/libswfdec/swfdec_buffer.c +++ b/libswfdec/swfdec_buffer.c @@ -177,6 +177,13 @@ swfdec_buffer_queue_free (SwfdecBufferQu void swfdec_buffer_queue_push (SwfdecBufferQueue * queue, SwfdecBuffer * buffer) { + g_return_if_fail (queue != NULL); + g_return_if_fail (buffer != NULL); + + if (buffer->length == 0) { + swfdec_buffer_unref (buffer); + return; + } queue->buffers = g_list_append (queue->buffers, buffer); queue->depth += buffer->length; } diff-tree b32e8c5b76f4dfde34c72057feb9d9970bea2e7a (from 3d7f4a9fd93c17adc999370d40eff49d1983f126) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 23 15:16:17 2007 +0100 export the entry format and rename it to SwfeditTokenEntry diff --git a/test/swfedit_token.c b/test/swfedit_token.c index bb1e76b..f3623fc 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -137,14 +137,6 @@ struct { { swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL }, }; -/*** STRUCTS ***/ - -typedef struct { - char * name; - SwfeditTokenType type; - gpointer value; -} Entry; - /*** GTK_TREE_MODEL ***/ #if 0 @@ -191,12 +183,12 @@ swfedit_token_get_iter (GtkTreeModel *tr { SwfeditToken *token = SWFEDIT_TOKEN (tree_model); guint i = gtk_tree_path_get_indices (path)[0]; - Entry *entry; + SwfeditTokenEntry *entry; REPORT; if (i > token->tokens->len) return FALSE; - entry = &g_array_index (token->tokens, Entry, i); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); if (gtk_tree_path_get_depth (path) > 1) { GtkTreePath *new; int j; @@ -232,7 +224,7 @@ swfedit_token_get_path (GtkTreeModel *tr guint i; SwfeditToken *parent = token->parent; for (i = 0; i < parent->tokens->len; i++) { - Entry *entry = &g_array_index (parent->tokens, Entry, i); + SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i); if (entry->type != SWFEDIT_TOKEN_OBJECT) continue; if (entry->value == token) @@ -249,7 +241,7 @@ swfedit_token_get_value (GtkTreeModel *t gint column, GValue *value) { SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); - Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); REPORT; switch (column) { @@ -289,12 +281,12 @@ static gboolean swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { SwfeditToken *token; - Entry *entry; + SwfeditTokenEntry *entry; REPORT; if (parent) { token = SWFEDIT_TOKEN (parent->user_data); - entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2)); if (entry->type != SWFEDIT_TOKEN_OBJECT) return FALSE; token = entry->value; @@ -311,7 +303,7 @@ static gboolean swfedit_token_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter) { SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); - Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); REPORT; return entry->type == SWFEDIT_TOKEN_OBJECT; @@ -321,7 +313,7 @@ static gint swfedit_token_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) { SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); - Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2)); REPORT; if (entry->type != SWFEDIT_TOKEN_OBJECT) @@ -336,12 +328,12 @@ swfedit_token_iter_nth_child (GtkTreeMod GtkTreeIter *parent, gint n) { SwfeditToken *token; - Entry *entry; + SwfeditTokenEntry *entry; REPORT; if (parent) { token = SWFEDIT_TOKEN (parent->user_data); - entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2)); if (entry->type != SWFEDIT_TOKEN_OBJECT) return FALSE; @@ -370,7 +362,7 @@ swfedit_token_iter_parent (GtkTreeModel return FALSE; for (i = 0; i < parent->tokens->len; i++) { - Entry *entry = &g_array_index (parent->tokens, Entry, i); + SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i); if (entry->type != SWFEDIT_TOKEN_OBJECT) continue; if (entry->value == token) @@ -411,7 +403,7 @@ swfedit_token_dispose (GObject *object) guint i; for (i = 0; i < token->tokens->len; i++) { - Entry *entry = &g_array_index (token->tokens, Entry, i); + SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); g_free (entry->name); if (converters[entry->type].free) converters[entry->type].free (entry->value); @@ -432,7 +424,7 @@ swfedit_token_class_init (SwfeditTokenCl static void swfedit_token_init (SwfeditToken *token) { - token->tokens = g_array_new (FALSE, FALSE, sizeof (Entry)); + token->tokens = g_array_new (FALSE, FALSE, sizeof (SwfeditTokenEntry)); } SwfeditToken * @@ -447,7 +439,7 @@ swfedit_token_new (void) void swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, gpointer value) { - Entry entry = { NULL, type, value }; + SwfeditTokenEntry entry = { NULL, type, value }; g_return_if_fail (SWFEDIT_IS_TOKEN (token)); g_return_if_fail (name != NULL); @@ -461,7 +453,7 @@ void swfedit_token_set (SwfeditToken *token, GtkTreeIter *iter, const char *value) { GtkTreeModel *model; - Entry *entry; + SwfeditTokenEntry *entry; guint i; gpointer new; GtkTreePath *path; @@ -473,7 +465,7 @@ swfedit_token_set (SwfeditToken *token, model = GTK_TREE_MODEL (token); token = iter->user_data; i = GPOINTER_TO_UINT (iter->user_data2); - entry = &g_array_index (token->tokens, Entry, i); + entry = &g_array_index (token->tokens, SwfeditTokenEntry, i); if (converters[entry->type].from_string == NULL) return; if (!converters[entry->type].from_string (value, &new)) diff --git a/test/swfedit_token.h b/test/swfedit_token.h index 1640027..5235d03 100644 --- a/test/swfedit_token.h +++ b/test/swfedit_token.h @@ -40,6 +40,8 @@ typedef enum { SWFEDIT_COLUMN_VALUE } SwfeditColumn; +typedef struct _SwfeditTokenEntry SwfeditTokenEntry; + typedef struct _SwfeditToken SwfeditToken; typedef struct _SwfeditTokenClass SwfeditTokenClass; @@ -50,12 +52,18 @@ typedef struct _SwfeditTokenClass Swfedi #define SWFEDIT_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass)) #define SWFEDIT_TOKEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass)) +struct _SwfeditTokenEntry { + char * name; + SwfeditTokenType type; + gpointer value; +}; + struct _SwfeditToken { GObject object; SwfeditToken * parent; /* parent of this token or NULL */ gchar * name; /* name of token */ - GArray * tokens; /* list of tokens */ + GArray * tokens; /* of SwfeditTokenEntry */ }; struct _SwfeditTokenClass { diff-tree 3d7f4a9fd93c17adc999370d40eff49d1983f126 (from 705e9e78e30cdb063445873c670cdbdfb918d07e) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 23 14:41:40 2007 +0100 add stubs for saving diff --git a/test/swfedit.c b/test/swfedit.c index 5dd2535..e16d645 100644 --- a/test/swfedit.c +++ b/test/swfedit.c @@ -25,6 +25,17 @@ #include "swfedit_file.h" static void +save (GtkButton *button, SwfeditFile *file) +{ + GError *error = NULL; + + if (!swfedit_file_save (file, &error)) { + g_printerr ("Error saving fils: %s\n", error->message); + g_error_free (error); + } +} + +static void cell_renderer_edited (GtkCellRenderer *renderer, char *path, char *new_text, SwfeditFile *file) { @@ -41,26 +52,29 @@ static gboolean open_window (char *filename) { SwfeditFile *file; - GtkWidget *window, *scroll, *treeview; + GtkWidget *window, *scroll, *box, *button, *treeview; GError *error = NULL; GtkTreeViewColumn *column; GtkCellRenderer *renderer; file = swfedit_file_new (filename, &error); if (file == NULL) { - g_printerr ("Error openeing file %s: %s\n", filename, error->message); + g_printerr ("Error opening file %s: %s\n", filename, error->message); g_error_free (error); return FALSE; } window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), filename); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + box = gtk_vbox_new (FALSE, 3); + gtk_container_add (GTK_CONTAINER (window), box); + scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_container_add (GTK_CONTAINER (window), scroll); + gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0); treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (file)); gtk_container_add (GTK_CONTAINER (scroll), treeview); - gtk_widget_show_all (window); renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Name", renderer, @@ -76,6 +90,11 @@ open_window (char *filename) gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + button = gtk_button_new_from_stock (GTK_STOCK_SAVE); + g_signal_connect (button, "clicked", G_CALLBACK (save), file); + gtk_box_pack_start (GTK_BOX (box), button, FALSE, TRUE, 0); + + gtk_widget_show_all (window); return TRUE; } diff --git a/test/swfedit_file.c b/test/swfedit_file.c index 7f2f240..d660655 100644 --- a/test/swfedit_file.c +++ b/test/swfedit_file.c @@ -37,8 +37,6 @@ swfedit_file_dispose (GObject *object) { SwfeditFile *file = SWFEDIT_FILE (object); - g_list_foreach (file->tags, (GFunc) g_object_unref, NULL); - g_list_free (file->tags); g_free (file->filename); G_OBJECT_CLASS (swfedit_file_parent_class)->dispose (object); @@ -210,3 +208,30 @@ swfedit_file_new (const char *filename, swfdec_buffer_unref (buffer); return file; } + +static SwfdecBuffer * +swfedit_file_write (SwfeditFile *file) +{ + return NULL; +} + +gboolean +swfedit_file_save (SwfeditFile *file, GError **error) +{ + SwfdecBuffer *buffer; + gboolean ret; + + g_return_val_if_fail (SWFEDIT_IS_FILE (file), FALSE); + + buffer = swfedit_file_write (file); + if (buffer == NULL) { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "Failed to render file"); + return FALSE; + } + ret = g_file_set_contents (file->filename, (char *) buffer->data, + buffer->length, error); + swfdec_buffer_unref (buffer); + return ret; +} + diff --git a/test/swfedit_file.h b/test/swfedit_file.h index 39a89c5..e904950 100644 --- a/test/swfedit_file.h +++ b/test/swfedit_file.h @@ -39,9 +39,6 @@ struct _SwfeditFile { SwfeditToken token; char * filename; /* name this file is saved to */ - - /* defined objects */ - GList * tags; /* ordered list of all tags in the file */ }; struct _SwfeditFileClass { @@ -53,6 +50,9 @@ GType swfedit_file_get_type (void); SwfeditFile * swfedit_file_new (const char * filename, GError ** error); +gboolean swfedit_file_save (SwfeditFile * file, + GError ** error); + G_END_DECLS diff-tree 705e9e78e30cdb063445873c670cdbdfb918d07e (from ce02af774584cc4bb00655d77b6e7e350b77402c) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 23 14:41:24 2007 +0100 change read/write to from_string/to_string diff --git a/test/swfedit_token.c b/test/swfedit_token.c index 2819b52..bb1e76b 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -12,7 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software + * License along with this library; if not, to_string to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ @@ -29,7 +29,7 @@ /*** CONVERTERS ***/ static gboolean -swfedit_binary_read (const char *s, gpointer* result) +swfedit_binary_from_string (const char *s, gpointer* result) { GByteArray *array = g_byte_array_new (); guint8 byte; @@ -71,7 +71,7 @@ swfedit_binary_read (const char *s, gpoi } static char * -swfedit_binary_write (gconstpointer value) +swfedit_binary_to_string (gconstpointer value) { guint i; const SwfdecBuffer *buffer = value; @@ -86,7 +86,7 @@ swfedit_binary_write (gconstpointer valu } static gboolean -swfedit_read_unsigned (const char *s, gulong max, gpointer* result) +swfedit_from_string_unsigned (const char *s, gulong max, gpointer* result) { char *end; gulong u; @@ -102,39 +102,39 @@ swfedit_read_unsigned (const char *s, gu } static gboolean -swfedit_uint8_read (const char *s, gpointer* result) +swfedit_uint8_from_string (const char *s, gpointer* result) { - return swfedit_read_unsigned (s, G_MAXUINT8, result); + return swfedit_from_string_unsigned (s, G_MAXUINT8, result); } static gboolean -swfedit_uint16_read (const char *s, gpointer* result) +swfedit_uint16_from_string (const char *s, gpointer* result) { - return swfedit_read_unsigned (s, G_MAXUINT16, result); + return swfedit_from_string_unsigned (s, G_MAXUINT16, result); } static gboolean -swfedit_uint32_read (const char *s, gpointer* result) +swfedit_uint32_from_string (const char *s, gpointer* result) { - return swfedit_read_unsigned (s, G_MAXUINT32, result); + return swfedit_from_string_unsigned (s, G_MAXUINT32, result); } static char * -swfedit_write_unsigned (gconstpointer value) +swfedit_to_string_unsigned (gconstpointer value) { return g_strdup_printf ("%u", GPOINTER_TO_UINT (value)); } struct { - gboolean (* read) (const char *s, gpointer *); - char * (* write) (gconstpointer value); + gboolean (* from_string) (const char *s, gpointer *); + char * (* to_string) (gconstpointer value); void (* free) (gpointer value); } converters[SWFEDIT_N_TOKENS] = { { NULL, NULL, g_object_unref }, - { swfedit_binary_read, swfedit_binary_write, (GDestroyNotify) swfdec_buffer_unref }, - { swfedit_uint8_read, swfedit_write_unsigned, NULL }, - { swfedit_uint16_read, swfedit_write_unsigned, NULL }, - { swfedit_uint32_read, swfedit_write_unsigned, NULL }, + { swfedit_binary_from_string, swfedit_binary_to_string, (GDestroyNotify) swfdec_buffer_unref }, + { swfedit_uint8_from_string, swfedit_to_string_unsigned, NULL }, + { swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL }, + { swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL }, }; /*** STRUCTS ***/ @@ -259,12 +259,12 @@ swfedit_token_get_value (GtkTreeModel *t return; case SWFEDIT_COLUMN_VALUE_VISIBLE: g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, converters[entry->type].write != NULL); + g_value_set_boolean (value, converters[entry->type].to_string != NULL); return; case SWFEDIT_COLUMN_VALUE: g_value_init (value, G_TYPE_STRING); - if (converters[entry->type].write) - g_value_take_string (value, converters[entry->type].write (entry->value)); + if (converters[entry->type].to_string) + g_value_take_string (value, converters[entry->type].to_string (entry->value)); return; default: break; @@ -474,9 +474,9 @@ swfedit_token_set (SwfeditToken *token, token = iter->user_data; i = GPOINTER_TO_UINT (iter->user_data2); entry = &g_array_index (token->tokens, Entry, i); - if (converters[entry->type].read == NULL) + if (converters[entry->type].from_string == NULL) return; - if (!converters[entry->type].read (value, &new)) + if (!converters[entry->type].from_string (value, &new)) return; if (converters[entry->type].free != NULL) converters[entry->type].free (entry->value); diff-tree ce02af774584cc4bb00655d77b6e7e350b77402c (from b5b36b679993d6c5576dc83f4deacd80fe2e5ce3) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 23 10:05:46 2007 +0100 enable editing of properties diff --git a/test/swfedit.c b/test/swfedit.c index 71a86aa..5dd2535 100644 --- a/test/swfedit.c +++ b/test/swfedit.c @@ -24,6 +24,19 @@ #include <gtk/gtk.h> #include "swfedit_file.h" +static void +cell_renderer_edited (GtkCellRenderer *renderer, char *path, + char *new_text, SwfeditFile *file) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (file), + &iter, path)) { + g_assert_not_reached (); + } + swfedit_token_set (SWFEDIT_TOKEN (file), &iter, new_text); +} + static gboolean open_window (char *filename) { @@ -57,6 +70,7 @@ open_window (char *filename) renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); + g_signal_connect (renderer, "edited", G_CALLBACK (cell_renderer_edited), file); column = gtk_tree_view_column_new_with_attributes ("Value", renderer, "text", SWFEDIT_COLUMN_VALUE, "visible", SWFEDIT_COLUMN_VALUE_VISIBLE, NULL); gtk_tree_view_column_set_resizable (column, TRUE); diff-tree b5b36b679993d6c5576dc83f4deacd80fe2e5ce3 (from d6679238c4929bf1d9cbb997b1ba9987c018e01e) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 23 10:05:35 2007 +0100 make parsing binary data work diff --git a/test/swfedit_token.c b/test/swfedit_token.c index 4e027eb..2819b52 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -45,13 +45,13 @@ swfedit_binary_read (const char *s, gpoi else break; s++; - byte *= 255; + byte *= 16; if (s[0] >= '0' && s[0] <= '9') - byte = s[0] - '0'; + byte += s[0] - '0'; else if (s[0] >= 'a' && s[0] <= 'f') - byte = s[0] + 10 - 'a'; + byte += s[0] + 10 - 'a'; else if (s[0] >= 'A' && s[0] <= 'F') - byte = s[0] + 10 - 'A'; + byte += s[0] + 10 - 'A'; else break; s++; diff-tree d6679238c4929bf1d9cbb997b1ba9987c018e01e (from 1af4da9dd02f8d5cd65b06bf25c6ac013bc26450) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 23 10:04:05 2007 +0100 ensure _get_nth_child works with token == NULL I hate it that you need -O2 to catch uninitialized variables diff --git a/test/swfedit_token.c b/test/swfedit_token.c index 704b98b..4e027eb 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -347,9 +347,11 @@ swfedit_token_iter_nth_child (GtkTreeMod return FALSE; token = entry->value; - if ((guint) n >= token->tokens->len) - return FALSE; + } else { + token = SWFEDIT_TOKEN (tree_model); } + if ((guint) n >= token->tokens->len) + return FALSE; iter->stamp = 0; /* FIXME */ iter->user_data = token; iter->user_data2 = GINT_TO_POINTER (n); diff-tree 1af4da9dd02f8d5cd65b06bf25c6ac013bc26450 (from 97ce107c67c3bcbd363eaf12e3669ca8226e4143) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 22:05:34 2007 +0100 print the actual tag name diff --git a/test/swfedit_file.c b/test/swfedit_file.c index 2ae8fa2..7f2f240 100644 --- a/test/swfedit_file.c +++ b/test/swfedit_file.c @@ -26,6 +26,7 @@ #include "libswfdec/swfdec_bits.h" #include "libswfdec/swfdec_buffer.h" #include "libswfdec/swfdec_debug.h" +#include "libswfdec/swfdec_swf_decoder.h" #include "swfedit_file.h" #include "swfedit_tag.h" @@ -152,7 +153,7 @@ swfedit_file_parse (SwfeditFile *file, S guint tag_len = x & 0x3f; SwfdecBuffer *buffer; SwfeditTag *item; - char *name; + if (tag_len == 0x3f) tag_len = swfdec_bits_get_u32 (bits); if (tag == 0) @@ -167,9 +168,9 @@ swfedit_file_parse (SwfeditFile *file, S return FALSE; } item = swfedit_tag_new (SWFEDIT_TOKEN (file), tag, buffer); - name = g_strdup_printf ("Tag %u", tag); - swfedit_token_add (SWFEDIT_TOKEN (file), name, SWFEDIT_TOKEN_OBJECT, item); - g_free (name); + swfedit_token_add (SWFEDIT_TOKEN (file), + swfdec_swf_decoder_get_tag_name (tag), + SWFEDIT_TOKEN_OBJECT, item); } swfdec_buffer_unref (next); return TRUE; diff-tree 97ce107c67c3bcbd363eaf12e3669ca8226e4143 (from bd5adea0669a5dbbbe75e887a400d6e538de0555) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 22:03:11 2007 +0100 make it not crash includes adding optional debugging help for the treeview diff --git a/test/swfedit.c b/test/swfedit.c index 76fa744..71a86aa 100644 --- a/test/swfedit.c +++ b/test/swfedit.c @@ -28,7 +28,7 @@ static gboolean open_window (char *filename) { SwfeditFile *file; - GtkWidget *window, *treeview; + GtkWidget *window, *scroll, *treeview; GError *error = NULL; GtkTreeViewColumn *column; GtkCellRenderer *renderer; @@ -42,8 +42,11 @@ open_window (char *filename) window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (window), scroll); + treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (file)); - gtk_container_add (GTK_CONTAINER (window), treeview); + gtk_container_add (GTK_CONTAINER (scroll), treeview); gtk_widget_show_all (window); renderer = gtk_cell_renderer_text_new (); diff --git a/test/swfedit_file.c b/test/swfedit_file.c index e995c1b..2ae8fa2 100644 --- a/test/swfedit_file.c +++ b/test/swfedit_file.c @@ -155,6 +155,8 @@ swfedit_file_parse (SwfeditFile *file, S char *name; if (tag_len == 0x3f) tag_len = swfdec_bits_get_u32 (bits); + if (tag == 0) + break; if (tag_len > 0) buffer = swfdec_bits_get_buffer (bits, tag_len); else @@ -164,7 +166,7 @@ swfedit_file_parse (SwfeditFile *file, S "Invalid contents in file"); return FALSE; } - item = swfedit_tag_new (tag, buffer); + item = swfedit_tag_new (SWFEDIT_TOKEN (file), tag, buffer); name = g_strdup_printf ("Tag %u", tag); swfedit_token_add (SWFEDIT_TOKEN (file), name, SWFEDIT_TOKEN_OBJECT, item); g_free (name); diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c index 9bbebeb..94ac4f9 100644 --- a/test/swfedit_tag.c +++ b/test/swfedit_tag.c @@ -49,12 +49,15 @@ swfedit_tag_init (SwfeditTag *tag) } SwfeditTag * -swfedit_tag_new (guint tag, SwfdecBuffer *buffer) +swfedit_tag_new (SwfeditToken *parent, guint tag, SwfdecBuffer *buffer) { SwfeditTag *item; + g_return_val_if_fail (SWFEDIT_IS_TOKEN (parent), NULL); + item = g_object_new (SWFEDIT_TYPE_TAG, NULL); item->tag = tag; + SWFEDIT_TOKEN (item)->parent = parent; swfedit_token_add (SWFEDIT_TOKEN (item), "contents", SWFEDIT_TOKEN_BINARY, buffer); return item; } diff --git a/test/swfedit_tag.h b/test/swfedit_tag.h index aad879e..07c11f2 100644 --- a/test/swfedit_tag.h +++ b/test/swfedit_tag.h @@ -47,7 +47,8 @@ struct _SwfeditTagClass { GType swfedit_tag_get_type (void); -SwfeditTag * swfedit_tag_new (guint tag, +SwfeditTag * swfedit_tag_new (SwfeditToken * parent, + guint tag, SwfdecBuffer * buffer); diff --git a/test/swfedit_token.c b/test/swfedit_token.c index 78951f2..704b98b 100644 --- a/test/swfedit_token.c +++ b/test/swfedit_token.c @@ -80,7 +80,7 @@ swfedit_binary_write (gconstpointer valu for (i = 0; i < buffer->length; i++) { if (i && i % 4 == 0) g_string_append_c (string, ' '); - g_string_append_printf (string, "%2X", buffer->data[i]); + g_string_append_printf (string, "%02X", buffer->data[i]); } return g_string_free (string, FALSE); } @@ -147,9 +147,15 @@ typedef struct { /*** GTK_TREE_MODEL ***/ +#if 0 +# define REPORT g_print ("%s\n", G_STRFUNC) +#else +# define REPORT +#endif static GtkTreeModelFlags swfedit_token_get_flags (GtkTreeModel *tree_model) { + REPORT; return 0; } @@ -158,12 +164,14 @@ swfedit_token_get_n_columns (GtkTreeMode { SwfeditToken *token = SWFEDIT_TOKEN (tree_model); + REPORT; return token->tokens->len; } static GType swfedit_token_get_column_type (GtkTreeModel *tree_model, gint index_) { + REPORT; switch (index_) { case SWFEDIT_COLUMN_NAME: return G_TYPE_STRING; @@ -185,6 +193,7 @@ swfedit_token_get_iter (GtkTreeModel *tr guint i = gtk_tree_path_get_indices (path)[0]; Entry *entry; + REPORT; if (i > token->tokens->len) return FALSE; entry = &g_array_index (token->tokens, Entry, i); @@ -199,7 +208,7 @@ swfedit_token_get_iter (GtkTreeModel *tr new = gtk_tree_path_new (); indices = gtk_tree_path_get_indices (path); for (j = 1; j < gtk_tree_path_get_depth (path); j++) { - gtk_tree_path_append_index (path, indices[j]); + gtk_tree_path_append_index (new, indices[j]); } ret = swfedit_token_get_iter (GTK_TREE_MODEL (entry->value), iter, new); gtk_tree_path_free (new); @@ -218,6 +227,7 @@ swfedit_token_get_path (GtkTreeModel *tr SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data2), -1); + REPORT; while (token->parent) { guint i; SwfeditToken *parent = token->parent; @@ -241,6 +251,7 @@ swfedit_token_get_value (GtkTreeModel *t SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + REPORT; switch (column) { case SWFEDIT_COLUMN_NAME: g_value_init (value, G_TYPE_STRING); @@ -266,6 +277,7 @@ swfedit_token_iter_next (GtkTreeModel *t { SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + REPORT; if ((guint) GPOINTER_TO_INT (iter->user_data2) + 1 >= token->tokens->len) return FALSE; @@ -276,14 +288,21 @@ swfedit_token_iter_next (GtkTreeModel *t static gboolean swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { - SwfeditToken *token = SWFEDIT_TOKEN (parent->user_data); - Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); - - if (entry->type != SWFEDIT_TOKEN_OBJECT) - return FALSE; + SwfeditToken *token; + Entry *entry; + REPORT; + if (parent) { + token = SWFEDIT_TOKEN (parent->user_data); + entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + token = entry->value; + } else { + token = SWFEDIT_TOKEN (tree_model); + } iter->stamp = 0; /* FIXME */ - iter->user_data = entry->value; + iter->user_data = token; iter->user_data2 = GINT_TO_POINTER (0); return TRUE; } @@ -294,6 +313,7 @@ swfedit_token_iter_has_child (GtkTreeMod SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + REPORT; return entry->type == SWFEDIT_TOKEN_OBJECT; } @@ -303,6 +323,7 @@ swfedit_token_iter_n_children (GtkTreeMo SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + REPORT; if (entry->type != SWFEDIT_TOKEN_OBJECT) return FALSE; @@ -317,6 +338,7 @@ swfedit_token_iter_nth_child (GtkTreeMod SwfeditToken *token; Entry *entry; + REPORT; if (parent) { token = SWFEDIT_TOKEN (parent->user_data); entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); @@ -341,6 +363,7 @@ swfedit_token_iter_parent (GtkTreeModel SwfeditToken *token = SWFEDIT_TOKEN (child->user_data); SwfeditToken *parent = token->parent; + REPORT; if (parent == NULL) return FALSE; @@ -352,7 +375,7 @@ swfedit_token_iter_parent (GtkTreeModel break; } iter->stamp = 0; /* FIXME */ - iter->user_data = token; + iter->user_data = parent; iter->user_data2 = GINT_TO_POINTER (i); return TRUE; } diff-tree bd5adea0669a5dbbbe75e887a400d6e538de0555 (from parents) Merge: 8c426c32f7343fff4ff23015f5f7eee647b5aee7 72caf9482e2e7eb4bdc6cc0fa7578beb31645bac Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 18:40:04 2007 +0100 Merge branch 'interpreter' of ssh://company@git.freedesktop.org/git/swfdec into interpreter diff-tree 72caf9482e2e7eb4bdc6cc0fa7578beb31645bac (from ac526c14b6a853304588e1c71ccc0ab709ac072e) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 18:34:59 2007 +0100 add a first shot at an swf file editor that is supposed to allow creating broken files for testing purposes when it's done diff --git a/test/Makefile.am b/test/Makefile.am index 01c4f45..d168cfd 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,10 @@ SUBDIRS = sound trace various -noinst_PROGRAMS = swfdec-extract dump parse +if WITH_GTK +noinst_PROGRAMS = swfdec-extract dump parse swfedit +else +noinst_PROGRAMS = swfdec-extract dump parse +endif dump_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js dump_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS) @@ -11,3 +15,16 @@ parse_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS swfdec_extract_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js swfdec_extract_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS) +swfedit_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(GTK_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js +swfedit_LDFLAGS = $(SWF_LIBS) $(GTK_LIBS) + +swfedit_SOURCES = \ + swfedit.c \ + swfedit_file.c \ + swfedit_tag.c \ + swfedit_token.c + +noinst_HEADERS = \ + swfedit_file.h \ + swfedit_tag.h \ + swfedit_token.h diff --git a/test/swfedit.c b/test/swfedit.c new file mode 100644 index 0000000..76fa744 --- /dev/null +++ b/test/swfedit.c @@ -0,0 +1,81 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gtk/gtk.h> +#include "swfedit_file.h" + +static gboolean +open_window (char *filename) +{ + SwfeditFile *file; + GtkWidget *window, *treeview; + GError *error = NULL; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + file = swfedit_file_new (filename, &error); + if (file == NULL) { + g_printerr ("Error openeing file %s: %s\n", filename, error->message); + g_error_free (error); + return FALSE; + } + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (file)); + gtk_container_add (GTK_CONTAINER (window), treeview); + gtk_widget_show_all (window); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Name", renderer, + "text", SWFEDIT_COLUMN_NAME, NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); + column = gtk_tree_view_column_new_with_attributes ("Value", renderer, + "text", SWFEDIT_COLUMN_VALUE, "visible", SWFEDIT_COLUMN_VALUE_VISIBLE, NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + + return TRUE; +} + +int +main (int argc, char **argv) +{ + gtk_init (&argc, &argv); + + if (argc <= 1) { + g_print ("Usage: %s FILENAME\n", argv[0]); + return 1; + } + if (open_window (argv[1])) { + gtk_main (); + return 0; + } else { + return 1; + } +} + diff --git a/test/swfedit_file.c b/test/swfedit_file.c new file mode 100644 index 0000000..e995c1b --- /dev/null +++ b/test/swfedit_file.c @@ -0,0 +1,209 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <zlib.h> + +#include "libswfdec/swfdec_bits.h" +#include "libswfdec/swfdec_buffer.h" +#include "libswfdec/swfdec_debug.h" +#include "swfedit_file.h" +#include "swfedit_tag.h" + +G_DEFINE_TYPE (SwfeditFile, swfedit_file, SWFEDIT_TYPE_TOKEN) + +static void +swfedit_file_dispose (GObject *object) +{ + SwfeditFile *file = SWFEDIT_FILE (object); + + g_list_foreach (file->tags, (GFunc) g_object_unref, NULL); + g_list_free (file->tags); + g_free (file->filename); + + G_OBJECT_CLASS (swfedit_file_parent_class)->dispose (object); +} + +static void * +zalloc (void *opaque, unsigned int items, unsigned int size) +{ + return g_malloc (items * size); +} + +static void +zfree (void *opaque, void *addr) +{ + g_free (addr); +} + +static SwfdecBuffer * +swfenc_file_inflate (SwfdecBits *bits, guint size) +{ + SwfdecBuffer *decoded, *encoded; + z_stream z; + int ret; + + encoded = swfdec_bits_get_buffer (bits, -1); + if (encoded == NULL) + return NULL; + decoded = swfdec_buffer_new_and_alloc (size); + z.zalloc = zalloc; + z.zfree = zfree; + z.opaque = NULL; + z.next_in = encoded->data; + z.avail_in = encoded->length; + z.next_out = decoded->data; + z.avail_out = decoded->length; + ret = inflateInit (&z); + SWFDEC_DEBUG ("inflateInit returned %d", ret); + if (ret >= Z_OK) { + ret = inflate (&z, Z_SYNC_FLUSH); + SWFDEC_DEBUG ("inflate returned %d", ret); + } + inflateEnd (&z); + swfdec_buffer_unref (encoded); + if (ret < Z_OK) { + swfdec_buffer_unref (decoded); + return NULL; + } + return decoded; +} + +static SwfdecBuffer * +swf_parse_header1 (SwfeditFile *file, SwfdecBits *bits, GError **error) +{ + guint sig1, sig2, sig3, bytes_total; + + sig1 = swfdec_bits_get_u8 (bits); + sig2 = swfdec_bits_get_u8 (bits); + sig3 = swfdec_bits_get_u8 (bits); + if ((sig1 != 'F' && sig1 != 'C') || sig2 != 'W' || sig3 != 'S') { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "This is not a SWF file"); + return NULL; + } + + swfedit_token_add (SWFEDIT_TOKEN (file), "version", SWFEDIT_TOKEN_UINT8, + GUINT_TO_POINTER (swfdec_bits_get_u8 (bits))); + bytes_total = swfdec_bits_get_u32 (bits); + + if (sig1 == 'C') { + /* compressed */ + SwfdecBuffer *ret = swfenc_file_inflate (bits, bytes_total); + if (ret == NULL) + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "Unable to uncompress file"); + return ret; + } else { + SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, -1); + if (ret == NULL) + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "File too small"); + return ret; + } +} + +static void +swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits) +{ + SwfdecRect rect; + + swfdec_bits_get_rect (bits, &rect); + swfdec_bits_syncbits (bits); + swfedit_token_add (SWFEDIT_TOKEN (file), "rate", SWFEDIT_TOKEN_UINT16, + GUINT_TO_POINTER (swfdec_bits_get_u16 (bits))); + swfedit_token_add (SWFEDIT_TOKEN (file), "frames", SWFEDIT_TOKEN_UINT16, + GUINT_TO_POINTER (swfdec_bits_get_u16 (bits))); +} + +static gboolean +swfedit_file_parse (SwfeditFile *file, SwfdecBits *bits, GError **error) +{ + SwfdecBuffer *next; + + next = swf_parse_header1 (file, bits, error); + if (next == NULL) + return FALSE; + swfdec_bits_init (bits, next); + swf_parse_header2 (file, bits); + + while (swfdec_bits_left (bits)) { + guint x = swfdec_bits_get_u16 (bits); + G_GNUC_UNUSED guint tag = (x >> 6) & 0x3ff; + guint tag_len = x & 0x3f; + SwfdecBuffer *buffer; + SwfeditTag *item; + char *name; + if (tag_len == 0x3f) + tag_len = swfdec_bits_get_u32 (bits); + if (tag_len > 0) + buffer = swfdec_bits_get_buffer (bits, tag_len); + else + buffer = swfdec_buffer_new (); + if (buffer == NULL) { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "Invalid contents in file"); + return FALSE; + } + item = swfedit_tag_new (tag, buffer); + name = g_strdup_printf ("Tag %u", tag); + swfedit_token_add (SWFEDIT_TOKEN (file), name, SWFEDIT_TOKEN_OBJECT, item); + g_free (name); + } + swfdec_buffer_unref (next); + return TRUE; +} + +static void +swfedit_file_class_init (SwfeditFileClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = swfedit_file_dispose; +} + +static void +swfedit_file_init (SwfeditFile *s) +{ +} + +SwfeditFile * +swfedit_file_new (const char *filename, GError **error) +{ + SwfeditFile *file; + SwfdecBuffer *buffer; + SwfdecBits bits; + + buffer = swfdec_buffer_new_from_file (filename, error); + if (buffer == NULL) + return NULL; + swfdec_bits_init (&bits, buffer); + file = g_object_new (SWFEDIT_TYPE_FILE, NULL); + file->filename = g_strdup (filename); + if (!swfedit_file_parse (file, &bits, error)) { + swfdec_buffer_unref (buffer); + g_object_unref (file); + return NULL; + } + swfdec_buffer_unref (buffer); + return file; +} diff --git a/test/swfedit_file.h b/test/swfedit_file.h new file mode 100644 index 0000000..39a89c5 --- /dev/null +++ b/test/swfedit_file.h @@ -0,0 +1,59 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __SWFEDIT_FILE_H__ +#define __SWFEDIT_FILE_H__ + +#include <libswfdec/swfdec_rect.h> +#include "swfedit_token.h" + +G_BEGIN_DECLS + +typedef struct _SwfeditFile SwfeditFile; +typedef struct _SwfeditFileClass SwfeditFileClass; + +#define SWFEDIT_TYPE_FILE (swfedit_file_get_type()) +#define SWFEDIT_IS_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_FILE)) +#define SWFEDIT_IS_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_FILE)) +#define SWFEDIT_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_FILE, SwfeditFile)) +#define SWFEDIT_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_FILE, SwfeditFileClass)) +#define SWFEDIT_FILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_FILE, SwfeditFileClass)) + +struct _SwfeditFile { + SwfeditToken token; + + char * filename; /* name this file is saved to */ + + /* defined objects */ + GList * tags; /* ordered list of all tags in the file */ +}; + +struct _SwfeditFileClass { + SwfeditTokenClass token_class; +}; + +GType swfedit_file_get_type (void); + +SwfeditFile * swfedit_file_new (const char * filename, + GError ** error); + + +G_END_DECLS + +#endif diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c new file mode 100644 index 0000000..9bbebeb --- /dev/null +++ b/test/swfedit_tag.c @@ -0,0 +1,61 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <gtk/gtk.h> +#include "swfedit_tag.h" + +G_DEFINE_TYPE (SwfeditTag, swfedit_tag, SWFEDIT_TYPE_TOKEN) + +static void +swfedit_tag_dispose (GObject *object) +{ + //SwfeditTag *tag = SWFEDIT_TAG (object); + + G_OBJECT_CLASS (swfedit_tag_parent_class)->dispose (object); +} + +static void +swfedit_tag_class_init (SwfeditTagClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = swfedit_tag_dispose; +} + +static void +swfedit_tag_init (SwfeditTag *tag) +{ +} + +SwfeditTag * +swfedit_tag_new (guint tag, SwfdecBuffer *buffer) +{ + SwfeditTag *item; + + item = g_object_new (SWFEDIT_TYPE_TAG, NULL); + item->tag = tag; + swfedit_token_add (SWFEDIT_TOKEN (item), "contents", SWFEDIT_TOKEN_BINARY, buffer); + return item; +} + diff --git a/test/swfedit_tag.h b/test/swfedit_tag.h new file mode 100644 index 0000000..aad879e --- /dev/null +++ b/test/swfedit_tag.h @@ -0,0 +1,56 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __SWFEDIT_TAG_H__ +#define __SWFEDIT_TAG_H__ + +#include <libswfdec/swfdec_buffer.h> +#include "swfedit_token.h" + +G_BEGIN_DECLS + +typedef struct _SwfeditTag SwfeditTag; +typedef struct _SwfeditTagClass SwfeditTagClass; + +#define SWFEDIT_TYPE_TAG (swfedit_tag_get_type()) +#define SWFEDIT_IS_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TAG)) +#define SWFEDIT_IS_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TAG)) +#define SWFEDIT_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TAG, SwfeditTag)) +#define SWFEDIT_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TAG, SwfeditTagClass)) +#define SWFEDIT_TAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TAG, SwfeditTagClass)) + +struct _SwfeditTag { + SwfeditToken token; + + guint tag; /* tag type */ +}; + +struct _SwfeditTagClass { + SwfeditTokenClass token_class; +}; + +GType swfedit_tag_get_type (void); + +SwfeditTag * swfedit_tag_new (guint tag, + SwfdecBuffer * buffer); + + +G_END_DECLS + +#endif diff --git a/test/swfedit_token.c b/test/swfedit_token.c new file mode 100644 index 0000000..78951f2 --- /dev/null +++ b/test/swfedit_token.c @@ -0,0 +1,464 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <gtk/gtk.h> +#include <libswfdec/swfdec_buffer.h> +#include "swfedit_token.h" + +/*** CONVERTERS ***/ + +static gboolean +swfedit_binary_read (const char *s, gpointer* result) +{ + GByteArray *array = g_byte_array_new (); + guint8 byte; + + while (g_ascii_isspace (*s)) s++; + do { + if (s[0] >= '0' && s[0] <= '9') + byte = s[0] - '0'; + else if (s[0] >= 'a' && s[0] <= 'f') + byte = s[0] + 10 - 'a'; + else if (s[0] >= 'A' && s[0] <= 'F') + byte = s[0] + 10 - 'A'; + else + break; + s++; + byte *= 255; + if (s[0] >= '0' && s[0] <= '9') + byte = s[0] - '0'; + else if (s[0] >= 'a' && s[0] <= 'f') + byte = s[0] + 10 - 'a'; + else if (s[0] >= 'A' && s[0] <= 'F') + byte = s[0] + 10 - 'A'; + else + break; + s++; + g_byte_array_append (array, &byte, 1); + while (g_ascii_isspace (*s)) s++; + } while (TRUE); + if (*s == '\0') { + SwfdecBuffer *buffer = swfdec_buffer_new (); + buffer->length = array->len; + buffer->data = array->data; + g_byte_array_free (array, FALSE); + *result = buffer; + return TRUE; + } + g_byte_array_free (array, TRUE); + return FALSE; +} + +static char * +swfedit_binary_write (gconstpointer value) +{ + guint i; + const SwfdecBuffer *buffer = value; + GString *string = g_string_new (""); + + for (i = 0; i < buffer->length; i++) { + if (i && i % 4 == 0) + g_string_append_c (string, ' '); + g_string_append_printf (string, "%2X", buffer->data[i]); + } + return g_string_free (string, FALSE); +} + +static gboolean +swfedit_read_unsigned (const char *s, gulong max, gpointer* result) +{ + char *end; + gulong u; + + g_assert (max <= G_MAXUINT); + u = strtoul (s, &end, 10); + if (*end != '\0') + return FALSE; + if (u > max) + return FALSE; + *result = GUINT_TO_POINTER ((guint) u); + return TRUE; +} + +static gboolean +swfedit_uint8_read (const char *s, gpointer* result) +{ + return swfedit_read_unsigned (s, G_MAXUINT8, result); +} + +static gboolean +swfedit_uint16_read (const char *s, gpointer* result) +{ + return swfedit_read_unsigned (s, G_MAXUINT16, result); +} + +static gboolean +swfedit_uint32_read (const char *s, gpointer* result) +{ + return swfedit_read_unsigned (s, G_MAXUINT32, result); +} + +static char * +swfedit_write_unsigned (gconstpointer value) +{ + return g_strdup_printf ("%u", GPOINTER_TO_UINT (value)); +} + +struct { + gboolean (* read) (const char *s, gpointer *); + char * (* write) (gconstpointer value); + void (* free) (gpointer value); +} converters[SWFEDIT_N_TOKENS] = { + { NULL, NULL, g_object_unref }, + { swfedit_binary_read, swfedit_binary_write, (GDestroyNotify) swfdec_buffer_unref }, + { swfedit_uint8_read, swfedit_write_unsigned, NULL }, + { swfedit_uint16_read, swfedit_write_unsigned, NULL }, + { swfedit_uint32_read, swfedit_write_unsigned, NULL }, +}; + +/*** STRUCTS ***/ + +typedef struct { + char * name; + SwfeditTokenType type; + gpointer value; +} Entry; + +/*** GTK_TREE_MODEL ***/ + +static GtkTreeModelFlags +swfedit_token_get_flags (GtkTreeModel *tree_model) +{ + return 0; +} + +static gint +swfedit_token_get_n_columns (GtkTreeModel *tree_model) +{ + SwfeditToken *token = SWFEDIT_TOKEN (tree_model); + + return token->tokens->len; +} + +static GType +swfedit_token_get_column_type (GtkTreeModel *tree_model, gint index_) +{ + switch (index_) { + case SWFEDIT_COLUMN_NAME: + return G_TYPE_STRING; + case SWFEDIT_COLUMN_VALUE_VISIBLE: + return G_TYPE_BOOLEAN; + case SWFEDIT_COLUMN_VALUE: + return G_TYPE_STRING; + default: + break; + } + g_assert_not_reached (); + return G_TYPE_NONE; +} + +static gboolean +swfedit_token_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) +{ + SwfeditToken *token = SWFEDIT_TOKEN (tree_model); + guint i = gtk_tree_path_get_indices (path)[0]; + Entry *entry; + + if (i > token->tokens->len) + return FALSE; + entry = &g_array_index (token->tokens, Entry, i); + if (gtk_tree_path_get_depth (path) > 1) { + GtkTreePath *new; + int j; + int *indices; + gboolean ret; + + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + new = gtk_tree_path_new (); + indices = gtk_tree_path_get_indices (path); + for (j = 1; j < gtk_tree_path_get_depth (path); j++) { + gtk_tree_path_append_index (path, indices[j]); + } + ret = swfedit_token_get_iter (GTK_TREE_MODEL (entry->value), iter, new); + gtk_tree_path_free (new); + return ret; + } else { + iter->stamp = 0; /* FIXME */ + iter->user_data = token; + iter->user_data2 = GINT_TO_POINTER (i); + return TRUE; + } +} + +static GtkTreePath * +swfedit_token_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data2), -1); + + while (token->parent) { + guint i; + SwfeditToken *parent = token->parent; + for (i = 0; i < parent->tokens->len; i++) { + Entry *entry = &g_array_index (parent->tokens, Entry, i); + if (entry->type != SWFEDIT_TOKEN_OBJECT) + continue; + if (entry->value == token) + break; + } + gtk_tree_path_prepend_index (path, i); + token = parent; + } + return path; +} + +static void +swfedit_token_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, + gint column, GValue *value) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + + switch (column) { + case SWFEDIT_COLUMN_NAME: + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, entry->name); + return; + case SWFEDIT_COLUMN_VALUE_VISIBLE: + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, converters[entry->type].write != NULL); + return; + case SWFEDIT_COLUMN_VALUE: + g_value_init (value, G_TYPE_STRING); + if (converters[entry->type].write) + g_value_take_string (value, converters[entry->type].write (entry->value)); + return; + default: + break; + } + g_assert_not_reached (); +} + +static gboolean +swfedit_token_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + + if ((guint) GPOINTER_TO_INT (iter->user_data2) + 1 >= token->tokens->len) + return FALSE; + + iter->user_data2++; + return TRUE; +} + +static gboolean +swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) +{ + SwfeditToken *token = SWFEDIT_TOKEN (parent->user_data); + Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); + + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + + iter->stamp = 0; /* FIXME */ + iter->user_data = entry->value; + iter->user_data2 = GINT_TO_POINTER (0); + return TRUE; +} + +static gboolean +swfedit_token_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + + return entry->type == SWFEDIT_TOKEN_OBJECT; +} + +static gint +swfedit_token_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter) +{ + SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data); + Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2)); + + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + + token = entry->value; + return token->tokens->len; +} + +static gboolean +swfedit_token_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, + GtkTreeIter *parent, gint n) +{ + SwfeditToken *token; + Entry *entry; + + if (parent) { + token = SWFEDIT_TOKEN (parent->user_data); + entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2)); + + if (entry->type != SWFEDIT_TOKEN_OBJECT) + return FALSE; + + token = entry->value; + if ((guint) n >= token->tokens->len) + return FALSE; + } + iter->stamp = 0; /* FIXME */ + iter->user_data = token; + iter->user_data2 = GINT_TO_POINTER (n); + return TRUE; +} + +static gboolean +swfedit_token_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) +{ + guint i; + SwfeditToken *token = SWFEDIT_TOKEN (child->user_data); + SwfeditToken *parent = token->parent; + + if (parent == NULL) + return FALSE; + + for (i = 0; i < parent->tokens->len; i++) { + Entry *entry = &g_array_index (parent->tokens, Entry, i); + if (entry->type != SWFEDIT_TOKEN_OBJECT) + continue; + if (entry->value == token) + break; + } + iter->stamp = 0; /* FIXME */ + iter->user_data = token; + iter->user_data2 = GINT_TO_POINTER (i); + return TRUE; +} + +static void +swfedit_token_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = swfedit_token_get_flags; + iface->get_n_columns = swfedit_token_get_n_columns; + iface->get_column_type = swfedit_token_get_column_type; + iface->get_iter = swfedit_token_get_iter; + iface->get_path = swfedit_token_get_path; + iface->get_value = swfedit_token_get_value; + iface->iter_next = swfedit_token_iter_next; + iface->iter_children = swfedit_token_iter_children; + iface->iter_has_child = swfedit_token_iter_has_child; + iface->iter_n_children = swfedit_token_iter_n_children; + iface->iter_nth_child = swfedit_token_iter_nth_child; + iface->iter_parent = swfedit_token_iter_parent; +} + +/*** SWFEDIT_TOKEN ***/ + +G_DEFINE_TYPE_WITH_CODE (SwfeditToken, swfedit_token, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, swfedit_token_tree_model_init)) + +static void +swfedit_token_dispose (GObject *object) +{ + SwfeditToken *token = SWFEDIT_TOKEN (object); + guint i; + + for (i = 0; i < token->tokens->len; i++) { + Entry *entry = &g_array_index (token->tokens, Entry, i); + g_free (entry->name); + if (converters[entry->type].free) + converters[entry->type].free (entry->value); + } + g_array_free (token->tokens, TRUE); + + G_OBJECT_CLASS (swfedit_token_parent_class)->dispose (object); +} + +static void +swfedit_token_class_init (SwfeditTokenClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = swfedit_token_dispose; +} + +static void +swfedit_token_init (SwfeditToken *token) +{ + token->tokens = g_array_new (FALSE, FALSE, sizeof (Entry)); +} + +SwfeditToken * +swfedit_token_new (void) +{ + SwfeditToken *token; + + token = g_object_new (SWFEDIT_TYPE_TOKEN, NULL); + return token; +} + +void +swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, gpointer value) +{ + Entry entry = { NULL, type, value }; + + g_return_if_fail (SWFEDIT_IS_TOKEN (token)); + g_return_if_fail (name != NULL); + g_return_if_fail (type < SWFEDIT_N_TOKENS); + + entry.name = g_strdup (name); + g_array_append_val (token->tokens, entry); +} + +void +swfedit_token_set (SwfeditToken *token, GtkTreeIter *iter, const char *value) +{ + GtkTreeModel *model; + Entry *entry; + guint i; + gpointer new; + GtkTreePath *path; + + g_return_if_fail (SWFEDIT_IS_TOKEN (token)); + g_return_if_fail (iter != NULL); + g_return_if_fail (value != NULL); + + model = GTK_TREE_MODEL (token); + token = iter->user_data; + i = GPOINTER_TO_UINT (iter->user_data2); + entry = &g_array_index (token->tokens, Entry, i); + if (converters[entry->type].read == NULL) + return; + if (!converters[entry->type].read (value, &new)) + return; + if (converters[entry->type].free != NULL) + converters[entry->type].free (entry->value); + entry->value = new; + + path = gtk_tree_model_get_path (model, iter); + gtk_tree_model_row_changed (model, path, iter); + gtk_tree_path_free (path); +} + diff --git a/test/swfedit_token.h b/test/swfedit_token.h new file mode 100644 index 0000000..1640027 --- /dev/null +++ b/test/swfedit_token.h @@ -0,0 +1,79 @@ +/* Swfedit + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __SWFEDIT_TOKEN_H__ +#define __SWFEDIT_TOKEN_H__ + +#include <gtk/gtk.h> +#include <libswfdec/swfdec_rect.h> + +G_BEGIN_DECLS + +typedef enum { + SWFEDIT_TOKEN_OBJECT, + SWFEDIT_TOKEN_BINARY, + SWFEDIT_TOKEN_UINT8, + SWFEDIT_TOKEN_UINT16, + SWFEDIT_TOKEN_UINT32, + SWFEDIT_N_TOKENS +} SwfeditTokenType; + +typedef enum { + SWFEDIT_COLUMN_NAME, + SWFEDIT_COLUMN_VALUE_VISIBLE, + SWFEDIT_COLUMN_VALUE +} SwfeditColumn; + +typedef struct _SwfeditToken SwfeditToken; +typedef struct _SwfeditTokenClass SwfeditTokenClass; + +#define SWFEDIT_TYPE_TOKEN (swfedit_token_get_type()) +#define SWFEDIT_IS_TOKEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TOKEN)) +#define SWFEDIT_IS_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TOKEN)) +#define SWFEDIT_TOKEN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TOKEN, SwfeditToken)) +#define SWFEDIT_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass)) +#define SWFEDIT_TOKEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass)) + +struct _SwfeditToken { + GObject object; + + SwfeditToken * parent; /* parent of this token or NULL */ + gchar * name; /* name of token */ + GArray * tokens; /* list of tokens */ +}; + +struct _SwfeditTokenClass { + GObjectClass object_class; +}; + +GType swfedit_token_get_type (void); + +SwfeditToken * swfedit_token_new (void); +void swfedit_token_add (SwfeditToken * token, + const char * name, + SwfeditTokenType type, + gpointer value); +void swfedit_token_set (SwfeditToken * token, + GtkTreeIter * iter, + const char * value); + + +G_END_DECLS + +#endif diff-tree ac526c14b6a853304588e1c71ccc0ab709ac072e (from 134ac8ae16f9e1cf5dc68f4ebb97bba74bed0235) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 18:32:04 2007 +0100 convert the parsing code to the recent SwfdecBits API diff --git a/libswfdec/swfdec_swf_decoder.c b/libswfdec/swfdec_swf_decoder.c index a43c9ac..6539921 100644 --- a/libswfdec/swfdec_swf_decoder.c +++ b/libswfdec/swfdec_swf_decoder.c @@ -206,10 +206,7 @@ swf_parse_header2 (SwfdecSwfDecoder * s) return SWFDEC_STATUS_NEEDBITS; } - s->b.buffer = buffer; - s->b.ptr = buffer->data; - s->b.idx = 0; - s->b.end = buffer->data + buffer->length; + swfdec_bits_init (&s->b, buffer); swfdec_bits_get_rect (&s->b, &rect); if (rect.x0 != 0.0 || rect.y0 != 0.0) @@ -239,7 +236,6 @@ swfdec_swf_decoder_parse (SwfdecDecoder { SwfdecSwfDecoder *s = SWFDEC_SWF_DECODER (dec); int ret = SWFDEC_STATUS_OK; - const unsigned char *endptr; SwfdecBuffer *buffer; s->b = s->parse; @@ -271,12 +267,7 @@ swfdec_swf_decoder_parse (SwfdecDecoder if (buffer == NULL) { return SWFDEC_STATUS_NEEDBITS; } - - s->b.buffer = buffer; - s->b.ptr = buffer->data; - s->b.idx = 0; - s->b.end = buffer->data + buffer->length; - + swfdec_bits_init (&s->b, buffer); x = swfdec_bits_get_u16 (&s->b); tag = (x >> 6) & 0x3ff; @@ -288,10 +279,7 @@ swfdec_swf_decoder_parse (SwfdecDecoder if (buffer == NULL) { return SWFDEC_STATUS_NEEDBITS; } - s->b.buffer = buffer; - s->b.ptr = buffer->data; - s->b.idx = 0; - s->b.end = buffer->data + buffer->length; + swfdec_bits_init (&s->b, buffer); swfdec_bits_get_u16 (&s->b); tag_len = swfdec_bits_get_u32 (&s->b); @@ -313,21 +301,11 @@ swfdec_swf_decoder_parse (SwfdecDecoder buffer = swfdec_buffer_queue_pull (s->input_queue, header_length); swfdec_buffer_unref (buffer); - if (tag_len > 0) { + if (tag_len > 0) buffer = swfdec_buffer_queue_pull (s->input_queue, tag_len); - s->b.buffer = buffer; - s->b.ptr = buffer->data; - s->b.idx = 0; - s->b.end = buffer->data + buffer->length; - endptr = s->b.ptr + tag_len; - } else { + else buffer = NULL; - s->b.buffer = NULL; - s->b.ptr = NULL; - s->b.idx = 0; - s->b.end = NULL; - endptr = NULL; - } + swfdec_bits_init (&s->b, buffer); func = swfdec_swf_decoder_get_tag_func (tag); if (func == NULL) { SWFDEC_WARNING ("tag function not implemented for %d %s", @@ -338,18 +316,10 @@ swfdec_swf_decoder_parse (SwfdecDecoder s->parse_sprite = NULL; swfdec_bits_syncbits (&s->b); - if (s->b.ptr < endptr) { + if (swfdec_bits_left (&s->b)) { SWFDEC_WARNING ("early finish (%d bytes) at %d, tag %d %s, length %d", - endptr - s->b.ptr, - swfdec_buffer_queue_get_offset (s->input_queue), tag, - swfdec_swf_decoder_get_tag_name (tag), tag_len); - //dumpbits (&s->b); - } - if (s->b.ptr > endptr) { - SWFDEC_WARNING - ("parse_overrun (%d bytes) at %d, tag %d %s, length %d", - s->b.ptr - endptr, + swfdec_bits_left (&s->b) / 8, swfdec_buffer_queue_get_offset (s->input_queue), tag, swfdec_swf_decoder_get_tag_name (tag), tag_len); } diff-tree 134ac8ae16f9e1cf5dc68f4ebb97bba74bed0235 (from 878ec656b0711cd19c11554d0617109a058af799) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 18:17:48 2007 +0100 allow NULL buffer in swfdec_bits_init and 0 length in swfdec_bits_get_buffer This simplifies error checking, since we catch errors in those cases anyway: - NULL buffer bits are like data bits that finished reading - 0 length get_buffer returns NULL, which is a valid return value for the error case diff --git a/libswfdec/swfdec_bits.c b/libswfdec/swfdec_bits.c index 72cc3df..1a7e402 100644 --- a/libswfdec/swfdec_bits.c +++ b/libswfdec/swfdec_bits.c @@ -31,16 +31,27 @@ #include "swfdec_rect.h" +/** + * swfdec_bits_init: + * @bits: a #SwfdecBits + * @buffer: buffer to use for data or NULL + * + * initializes @bits for use with the data in @buffer. The buffer will not be + * referenced, so you are responsible for keeping it around while @bits is used. + **/ void swfdec_bits_init (SwfdecBits *bits, SwfdecBuffer *buffer) { g_return_if_fail (bits != NULL); - g_return_if_fail (buffer != NULL); - bits->buffer = buffer; - bits->ptr = buffer->data; - bits->idx = 0; - bits->end = buffer->data + buffer->length; + if (buffer) { + bits->buffer = buffer; + bits->ptr = buffer->data; + bits->idx = 0; + bits->end = buffer->data + buffer->length; + } else { + memset (bits, 0, sizeof (SwfdecBits)); + } } /** @@ -567,7 +578,7 @@ swfdec_bits_get_buffer (SwfdecBits *bits { SwfdecBuffer *buffer; - g_return_val_if_fail (len > 0 || len == -1, NULL); + g_return_val_if_fail (len >= -1, NULL); if (len > 0) { SWFDEC_BYTES_CHECK (bits, (unsigned int) len); @@ -575,9 +586,9 @@ swfdec_bits_get_buffer (SwfdecBits *bits swfdec_bits_syncbits (bits); len = bits->end - bits->ptr; g_assert (len >= 0); - if (len == 0) - return NULL; } + if (len == 0) + return NULL; if (bits->buffer) { buffer = swfdec_buffer_new_subbuffer (bits->buffer, bits->ptr - bits->buffer->data, len); } else { diff-tree 8c426c32f7343fff4ff23015f5f7eee647b5aee7 (from f2e4bc2ff2bfa289f325e525619b79dcf4815f9c) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 10:54:05 2007 +0100 implement Increment and Decrement diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 909cba4..171877f 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -753,6 +753,26 @@ swfdec_action_if (JSContext *cx, guint a return JS_TRUE; } +static JSBool +swfdec_action_decrement (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d; + + d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + d--; + return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); +} + +static JSBool +swfdec_action_increment (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d; + + d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + d++; + return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); +} + /*** PRINT FUNCTIONS ***/ static char * @@ -967,8 +987,8 @@ static const SwfdecActionSpec actions[25 [0x4d] = { "Swap", NULL }, [0x4e] = { "GetMember", NULL, 2, 1, { NULL, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member } }, [0x4f] = { "SetMember", NULL, 3, 0, { NULL, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member } }, - [0x50] = { "Increment", NULL }, - [0x51] = { "Decrement", NULL }, + [0x50] = { "Increment", NULL, 1, 1, { NULL, NULL, swfdec_action_increment, swfdec_action_increment, swfdec_action_increment } }, + [0x51] = { "Decrement", NULL, 1, 1, { NULL, NULL, swfdec_action_decrement, swfdec_action_decrement, swfdec_action_decrement } }, [0x52] = { "CallMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_call_method, swfdec_action_call_method, swfdec_action_call_method } }, [0x53] = { "NewMethod", NULL }, /* version 6 */ diff-tree f2e4bc2ff2bfa289f325e525619b79dcf4815f9c (from 568f6fdf0b44ea7cfcc87b33ed4ac09e88bbd47e) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 22 10:23:59 2007 +0100 Implement Jump, If and Not Also includes a fix to voncert booleans to numbers correctly 11/44 failures diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 104af78..909cba4 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -527,6 +527,8 @@ swfdec_action_to_number (JSContext *cx, return JSVAL_TO_INT (val); } else if (JSVAL_IS_DOUBLE (val)) { return *JSVAL_TO_DOUBLE (val); + } else if (JSVAL_IS_BOOLEAN (val)) { + return JSVAL_TO_BOOLEAN (val); } else { return 0; } @@ -704,9 +706,76 @@ swfdec_action_new_comparison_7 (JSContex return JS_TRUE; } +static JSBool +swfdec_action_not_4 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d; + + d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + cx->fp->sp[-1] = INT_TO_JSVAL (d == 0 ? 1 : 0); + return JS_TRUE; +} + +static JSBool +swfdec_action_not_5 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d; + + d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + cx->fp->sp[-1] = d == 0 ? JSVAL_TRUE : JSVAL_FALSE; + return JS_TRUE; +} + +static JSBool +swfdec_action_jump (JSContext *cx, guint action, const guint8 *data, guint len) +{ + if (len != 2) { + SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len); + return JS_FALSE; + } + cx->fp->pc += 4 + GINT16_FROM_LE (*((gint16*) data)); + return JS_TRUE; +} + +static JSBool +swfdec_action_if (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d; + + if (len != 2) { + SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len); + return JS_FALSE; + } + d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + cx->fp->sp--; + if (d != 0) + cx->fp->pc += 4 + GINT16_FROM_LE (*((gint16*) data)); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_if (guint action, const guint8 *data, guint len) +{ + if (len != 2) { + SWFDEC_ERROR ("If action length invalid (is %u, should be 2", len); + return NULL; + } + return g_strdup_printf ("If %d", GINT16_FROM_LE (*((gint16*) data))); +} + +static char * +swfdec_action_print_jump (guint action, const guint8 *data, guint len) +{ + if (len != 2) { + SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len); + return NULL; + } + return g_strdup_printf ("Jump %d", GINT16_FROM_LE (*((gint16*) data))); +} + +static char * swfdec_action_print_push (guint action, const guint8 *data, guint len) { gboolean first = TRUE; @@ -844,7 +913,7 @@ static const SwfdecActionSpec actions[25 [0x0f] = { "Less", NULL }, [0x10] = { "And", NULL }, [0x11] = { "Or", NULL }, - [0x12] = { "Not", NULL }, + [0x12] = { "Not", NULL, 1, 1, { NULL, swfdec_action_not_4, swfdec_action_not_5, swfdec_action_not_5, swfdec_action_not_5 } }, [0x13] = { "StringEquals", NULL }, [0x14] = { "StringLength", NULL }, [0x15] = { "StringExtract", NULL }, @@ -938,12 +1007,12 @@ static const SwfdecActionSpec actions[25 [0x94] = { "With", NULL }, /* version 4 */ [0x96] = { "Push", swfdec_action_print_push, 0, -1, { NULL, swfdec_action_push, swfdec_action_push, swfdec_action_push, swfdec_action_push } }, - [0x99] = { "Jump", NULL }, + [0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } }, [0x9a] = { "GetURL2", NULL }, /* version 5 */ [0x9b] = { "DefineFunction", NULL }, /* version 4 */ - [0x9d] = { "If", NULL }, + [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } }, [0x9e] = { "Call", NULL }, [0x9f] = { "GotoFrame2", NULL } }; diff-tree 568f6fdf0b44ea7cfcc87b33ed4ac09e88bbd47e (from e06e79a0c20256854b9073ee7c73a047e81dd820) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 21 20:48:06 2007 +0100 fix binary ops for undefined2-7.swf 13/44 failures diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 3bbd168..104af78 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -540,8 +540,15 @@ swfdec_action_binary (JSContext *cx, gui rval = cx->fp->sp[-1]; lval = cx->fp->sp[-2]; - l = swfdec_action_to_number (cx, lval); - r = swfdec_action_to_number (cx, rval); + if (((SwfdecScript *) cx->fp->swf)->version < 7) { + l = swfdec_action_to_number (cx, lval); + r = swfdec_action_to_number (cx, rval); + } else { + if (!JS_ValueToNumber(cx, lval, &l) || + !JS_ValueToNumber(cx, rval, &r)) + return JS_FALSE; + } + cx->fp->sp--; switch (action) { case 0x0a: l = l + r; @@ -557,17 +564,22 @@ swfdec_action_binary (JSContext *cx, gui JSString *str = JS_InternString (cx, "#ERROR#"); if (str == NULL) return JS_FALSE; - cx->fp->sp--; cx->fp->sp[-1] = STRING_TO_JSVAL (str); return JS_TRUE; } + if (((SwfdecScript *) cx->fp->swf)->version >= 7 && + JSVAL_IS_VOID (rval)) { + cx->fp->sp[-1] = DOUBLE_TO_JSVAL (r < 0 ? + cx->runtime->jsNegativeInfinity : + cx->runtime->jsPositiveInfinity); + return JS_TRUE; + } l = l / r; break; default: g_assert_not_reached (); return r; } - cx->fp->sp--; return JS_NewNumberValue (cx, l, &cx->fp->sp[-1]); } diff-tree e06e79a0c20256854b9073ee7c73a047e81dd820 (from 659db3d36cca2f586498ba8dd554f17dd50906f4) Author: Benjamin Otte <otte@gnome.org> Date: Sun Jan 21 19:24:27 2007 +0100 implement Less2 and Greater actions and fix a big bug The code used to always execute the v7 script. 14/44 failues diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 5b9f960..3bbd168 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -651,6 +651,47 @@ swfdec_action_set_member (JSContext *cx, return JS_TRUE; } +static JSBool +swfdec_action_new_comparison_6 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval lval, rval; + double d, d2; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + cx->fp->sp--; + d = swfdec_action_to_number (cx, lval); + d2 = swfdec_action_to_number (cx, rval); + if (action == 0x48) + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (d < d2); + else + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (d > d2); + return JS_TRUE; +} + +static JSBool +swfdec_action_new_comparison_7 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval lval, rval; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + cx->fp->sp--; + if (JSVAL_IS_VOID (rval) || JSVAL_IS_VOID (lval)) { + cx->fp->sp[-1] = JSVAL_VOID; + } else if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { + int comp = JS_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)); + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (action == 0x48 ? comp < 0 : comp > 0); + } else { + double d, d2; + if (!JS_ValueToNumber(cx, lval, &d) || + !JS_ValueToNumber(cx, rval, &d2)) + return JS_FALSE; + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (action == 0x48 ? d < d2 : d > d2); + } + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -762,7 +803,7 @@ swfdec_action_print_wait_for_frame (guin /* defines minimum and maximum versions for which we have seperate scripts */ #define MINSCRIPTVERSION 3 #define MAXSCRIPTVERSION 7 -#define EXTRACT_VERSION(v) MAX ((v) - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION) +#define EXTRACT_VERSION(v) MIN ((v) - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION) typedef JSBool (* SwfdecActionExec) (JSContext *cx, guint action, const guint8 *data, guint len); typedef struct { @@ -837,7 +878,7 @@ static const SwfdecActionSpec actions[25 [0x45] = { "TargetPath", NULL }, [0x46] = { "Enumerate", NULL }, [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, NULL, NULL, swfdec_action_add2_7 } }, - [0x48] = { "Less2", NULL }, + [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, [0x49] = { "Equals2", NULL }, [0x4a] = { "ToNumber", NULL }, [0x4b] = { "ToString", NULL }, @@ -861,7 +902,7 @@ static const SwfdecActionSpec actions[25 [0x65] = { "BitURShift", NULL }, /* version 6 */ [0x66] = { "StrictEquals", NULL }, - [0x67] = { "Greater", NULL }, + [0x67] = { "Greater", NULL, 2, 1, { NULL, NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, [0x68] = { "StringGreater", NULL }, /* version 7 */ [0x69] = { "Extends", NULL }, diff-tree 659db3d36cca2f586498ba8dd554f17dd50906f4 (from 39276bcb05d190d1fc6a0c35490774ee309f4ffb) Author: Benjamin Otte <otte@gnome.org> Date: Sat Jan 20 17:01:06 2007 +0100 Fix case handling (don't make it global anymore) and implement SetVariable with this there's 17/44 failures diff --git a/libswfdec/js/jsatom.c b/libswfdec/js/jsatom.c index f0816b2..c4c85b7 100644 --- a/libswfdec/js/jsatom.c +++ b/libswfdec/js/jsatom.c @@ -673,10 +673,10 @@ out: JSAtom * js_AtomizeString(JSContext *cx, JSString *str, uintN flags) { - if (cx->caseSensitive) - return js_AtomizeStringWithCompare (cx, str, flags, js_compare_atom_keys); - else + if (flags & ATOM_NOCASE) return js_AtomizeStringWithCompare (cx, str, flags, js_compare_atom_keys_no_case); + else + return js_AtomizeStringWithCompare (cx, str, flags, js_compare_atom_keys); } JS_FRIEND_API(JSAtom *) diff --git a/libswfdec/js/jsatom.h b/libswfdec/js/jsatom.h index 6f486c3..d9d2025 100644 --- a/libswfdec/js/jsatom.h +++ b/libswfdec/js/jsatom.h @@ -58,6 +58,7 @@ JS_BEGIN_EXTERN_C #define ATOM_PINNED 0x01 /* atom is pinned against GC */ #define ATOM_INTERNED 0x02 /* pinned variant for JS_Intern* API */ #define ATOM_MARK 0x04 /* atom is reachable via GC */ +#define ATOM_NOCASE 0x20 /* treat atom case-insensitive */ #define ATOM_NOCOPY 0x40 /* don't copy atom string bytes */ #define ATOM_TMPSTR 0x80 /* internal, to avoid extra string */ diff --git a/libswfdec/swfdec_edittext_movie.c b/libswfdec/swfdec_edittext_movie.c index 421f6bc..e3d2119 100644 --- a/libswfdec/swfdec_edittext_movie.c +++ b/libswfdec/swfdec_edittext_movie.c @@ -80,7 +80,7 @@ swfdec_edit_text_movie_iterate (SwfdecMo jsobj = swfdec_scriptable_get_object (parent); if (jsobj == NULL) return; - val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable); + val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable, FALSE); if (JSVAL_IS_VOID (val)) return; @@ -110,7 +110,7 @@ swfdec_edit_text_movie_init_movie (Swfde if (jsobj == NULL) return; if (text->text->variable_prefix) { - val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable_prefix); + val = swfdec_js_eval (parent->jscx, jsobj, text->text->variable_prefix, FALSE); if (!JSVAL_IS_OBJECT (val)) return; jsobj = JSVAL_TO_OBJECT (val); diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index cf14f65..bbd6a43 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -300,29 +300,26 @@ fail: static JSBool swfdec_js_eval_get_property (JSContext *cx, JSObject *obj, - const char *name, gboolean initial, jsval *ret) + const char *name, gboolean initial, gboolean ignore_case, jsval *ret) { JSAtom *atom; JSObject *pobj; JSProperty *prop; - if (!JS_GetProperty (cx, obj, name, ret)) - return JS_FALSE; - if (!JSVAL_IS_VOID (*ret)) - return JS_TRUE; - if (!initial) - return JS_FALSE; - - atom = js_Atomize(cx, name, strlen(name), 0); + atom = js_Atomize (cx, name, strlen(name), ignore_case ? ATOM_NOCASE : 0); if (!atom) return JS_FALSE; - if (!js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) - return JS_FALSE; - if (!prop) - return JS_FALSE; - if (pobj) - obj = pobj; - return OBJ_GET_PROPERTY (cx, obj, (jsid) prop->id, ret); + if (initial) { + return OBJ_GET_PROPERTY (cx, obj, (jsid) atom, ret); + } else { + if (!js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop)) + return JS_FALSE; + if (!prop) + return JS_FALSE; + if (pobj) + obj = pobj; + return OBJ_GET_PROPERTY (cx, obj, (jsid) prop->id, ret); + } } /** @@ -330,6 +327,7 @@ swfdec_js_eval_get_property (JSContext * * @cx: a #JSContext * @obj: #JSObject to use as a source for evaluating * @str: The string to evaluate + * @ignore_case: TRUE for case insensitive evaluation * * This function works like the Actionscript eval function used on @obj. * It handles both slash-style and dot-style notation. @@ -337,7 +335,8 @@ swfdec_js_eval_get_property (JSContext * * Returns: the value or JSVAL_VOID if no value was found. **/ jsval -swfdec_js_eval (JSContext *cx, JSObject *obj, const char *str) +swfdec_js_eval (JSContext *cx, JSObject *obj, const char *str, + gboolean ignore_case) { jsval cur; char *work = NULL; @@ -365,12 +364,12 @@ swfdec_js_eval (JSContext *cx, JSObject obj = JSVAL_TO_OBJECT (cur); if (dot) { char *name = g_strndup (str, dot - str); - if (!swfdec_js_eval_get_property (cx, obj, name, initial, &cur)) + if (!swfdec_js_eval_get_property (cx, obj, name, initial, ignore_case, &cur)) goto out; g_free (name); str = dot + 1; } else { - if (!swfdec_js_eval_get_property (cx, obj, str, initial, &cur)) + if (!swfdec_js_eval_get_property (cx, obj, str, initial, ignore_case, &cur)) goto out; str = NULL; } @@ -384,3 +383,5 @@ out: g_free (work); return JSVAL_VOID; } + + diff --git a/libswfdec/swfdec_js.h b/libswfdec/swfdec_js.h index ced8046..47e97ff 100644 --- a/libswfdec/swfdec_js.h +++ b/libswfdec/swfdec_js.h @@ -49,7 +49,8 @@ void swfdec_js_movie_remove_property (S char * swfdec_js_slash_to_dot (const char * slash_str); jsval swfdec_js_eval (JSContext * cx, JSObject * obj, - const char * str); + const char * str, + gboolean ignore_case); /* support functions */ const char * swfdec_js_to_string (JSContext * cx, diff --git a/libswfdec/swfdec_js_global.c b/libswfdec/swfdec_js_global.c index 328d74d..27522c1 100644 --- a/libswfdec/swfdec_js_global.c +++ b/libswfdec/swfdec_js_global.c @@ -33,7 +33,7 @@ swfdec_js_global_eval (JSContext *cx, JS const char *bytes = swfdec_js_to_string (cx, argv[0]); if (bytes == NULL) return JS_FALSE; - *rval = swfdec_js_eval (cx, obj, bytes); + *rval = swfdec_js_eval (cx, obj, bytes, FALSE); } else { *rval = argv[0]; } diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 23ca8ef..5b9f960 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -315,7 +315,26 @@ swfdec_action_get_variable (JSContext *c s = swfdec_js_to_string (cx, cx->fp->sp[-1]); if (s == NULL) return JS_FALSE; - cx->fp->sp[-1] = swfdec_js_eval (cx, cx->fp->scopeChain, s); + cx->fp->sp[-1] = swfdec_js_eval (cx, cx->fp->scopeChain, s, + ((SwfdecScript *) cx->fp->swf)->version < 7); + return JS_TRUE; +} + +static JSBool +swfdec_action_set_variable (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *s; + + s = swfdec_js_to_string (cx, cx->fp->sp[-2]); + if (s == NULL) + return JS_FALSE; + + if (strpbrk (s, "./:")) { + SWFDEC_WARNING ("FIXME: implement paths"); + } + if (!JS_SetProperty (cx, cx->fp->scopeChain, s, &cx->fp->sp[-1])) + return JS_FALSE; + cx->fp->sp -= 2; return JS_TRUE; } @@ -425,7 +444,8 @@ swfdec_eval_jsval (JSContext *cx, JSObje const char *bytes = swfdec_js_to_string (cx, *val); if (bytes == NULL) return JS_FALSE; - *val = swfdec_js_eval (cx, obj, bytes); + *val = swfdec_js_eval (cx, obj, bytes, + ((SwfdecScript *) cx->fp->swf)->version < 7); } else { *val = OBJECT_TO_JSVAL (obj); } @@ -500,6 +520,57 @@ out: return JS_TRUE; } +static double +swfdec_action_to_number (JSContext *cx, jsval val) +{ + if (JSVAL_IS_INT (val)) { + return JSVAL_TO_INT (val); + } else if (JSVAL_IS_DOUBLE (val)) { + return *JSVAL_TO_DOUBLE (val); + } else { + return 0; + } +} + +static JSBool +swfdec_action_binary (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval lval, rval; + double l, r; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + l = swfdec_action_to_number (cx, lval); + r = swfdec_action_to_number (cx, rval); + switch (action) { + case 0x0a: + l = l + r; + break; + case 0x0b: + l = l - r; + break; + case 0x0c: + l = l * r; + break; + case 0x0d: + if (r == 0 && ((SwfdecScript *) cx->fp->swf)->version < 5) { + JSString *str = JS_InternString (cx, "#ERROR#"); + if (str == NULL) + return JS_FALSE; + cx->fp->sp--; + cx->fp->sp[-1] = STRING_TO_JSVAL (str); + return JS_TRUE; + } + l = l / r; + break; + default: + g_assert_not_reached (); + return r; + } + cx->fp->sp--; + return JS_NewNumberValue (cx, l, &cx->fp->sp[-1]); +} + static JSBool swfdec_action_add2_7 (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -539,7 +610,7 @@ swfdec_action_add2_7 (JSContext *cx, gui return JS_FALSE; d += d2; cx->fp->sp--; - return JS_NewDoubleValue(cx, d, &cx->fp->sp[-1]); + return JS_NewNumberValue(cx, d, &cx->fp->sp[-1]); } return JS_TRUE; } @@ -712,10 +783,10 @@ static const SwfdecActionSpec actions[25 [0x08] = { "ToggleQuality", NULL }, [0x09] = { "StopSounds", NULL }, /* version 4 */ - [0x0a] = { "Add", NULL }, - [0x0b] = { "Subtract", NULL }, - [0x0c] = { "Multiply", NULL }, - [0x0d] = { "Divide", NULL }, + [0x0a] = { "Add", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, + [0x0b] = { "Subtract", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, + [0x0c] = { "Multiply", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, + [0x0d] = { "Divide", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } }, [0x0e] = { "Equals", NULL }, [0x0f] = { "Less", NULL }, [0x10] = { "And", NULL }, @@ -727,7 +798,7 @@ static const SwfdecActionSpec actions[25 [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } }, [0x18] = { "ToInteger", NULL }, [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, - [0x1d] = { "SetVariable", NULL }, + [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } }, [0x20] = { "SetTarget2", NULL }, [0x21] = { "StringAdd", NULL }, [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } }, diff-tree 39276bcb05d190d1fc6a0c35490774ee309f4ffb (from 41d6a77090dff7583e4a61937120db79d1c4c547) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 22:14:26 2007 +0100 fix SetMember 20/44 failures diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 0256d8c..23ca8ef 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -427,7 +427,7 @@ swfdec_eval_jsval (JSContext *cx, JSObje return JS_FALSE; *val = swfdec_js_eval (cx, obj, bytes); } else { - SWFDEC_ERROR ("huh?"); + *val = OBJECT_TO_JSVAL (obj); } return JS_TRUE; } @@ -475,7 +475,7 @@ swfdec_action_set_property (JSContext *c JSObject *jsobj; guint32 id; - val = cx->fp->sp[-2]; + val = cx->fp->sp[-3]; if (!swfdec_eval_jsval (cx, cx->fp->scopeChain, &val)) return JS_FALSE; movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE); @@ -483,7 +483,7 @@ swfdec_action_set_property (JSContext *c SWFDEC_WARNING ("specified target does not reference a movie clip"); goto out; } - if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &id)) + if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &id)) return JS_FALSE; if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) @@ -492,7 +492,7 @@ swfdec_action_set_property (JSContext *c if (!(jsobj = swfdec_scriptable_get_object (SWFDEC_SCRIPTABLE (movie)))) return JS_FALSE; - if (!JS_SetProperty (cx, jsobj, properties[id], &cx->fp->sp[-3])) + if (!JS_SetProperty (cx, jsobj, properties[id], &cx->fp->sp[-1])) return JS_FALSE; out: diff-tree 41d6a77090dff7583e4a61937120db79d1c4c547 (from f07034751126d85a58b48ff77bbf57c5dc8021ca) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 21:17:45 2007 +0100 push a double, not a float diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 583c2f1..0256d8c 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -251,7 +251,7 @@ swfdec_action_push (JSContext *cx, guint break; case 6: /* double */ { - double d = swfdec_bits_get_float (&bits); + double d = swfdec_bits_get_double (&bits); if (!JS_NewDoubleValue (cx, d, cx->fp->sp)) return JS_FALSE; cx->fp->sp++; diff-tree f07034751126d85a58b48ff77bbf57c5dc8021ca (from 34c98c5cf9deb0b5fc10f0cbee7bf368f3653000) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 21:16:28 2007 +0100 fix string Add2 diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index e4bf0d4..583c2f1 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -520,11 +520,11 @@ swfdec_action_add2_7 (JSContext *cx, gui JSString *str, *str2; if (cond) { str = JSVAL_TO_STRING (lval); - if ((str2 = js_ValueToString (cx, rval)) != NULL) + if ((str2 = js_ValueToString (cx, rval)) == NULL) return JS_FALSE; } else { str2 = JSVAL_TO_STRING (rval); - if ((str = js_ValueToString (cx, lval)) != NULL) + if ((str = js_ValueToString (cx, lval)) == NULL) return JS_FALSE; } str = js_ConcatStrings (cx, str, str2); diff-tree 34c98c5cf9deb0b5fc10f0cbee7bf368f3653000 (from 756c3c6c257d890fd5b35221ab7451017bb56d03) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 21:16:11 2007 +0100 implement SetMember diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 8f073b7..e4bf0d4 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -563,6 +563,23 @@ swfdec_action_get_member (JSContext *cx, return JS_TRUE; } +static JSBool +swfdec_action_set_member (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *s; + + s = swfdec_js_to_string (cx, cx->fp->sp[-2]); + if (s == NULL) + return JS_FALSE; + + if (JSVAL_IS_OBJECT (cx->fp->sp[-3])) { + if (!JS_SetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-3]), s, &cx->fp->sp[-1])) + return JS_FALSE; + } + cx->fp->sp -= 3; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -756,7 +773,7 @@ static const SwfdecActionSpec actions[25 [0x4c] = { "PushDuplicate", NULL }, [0x4d] = { "Swap", NULL }, [0x4e] = { "GetMember", NULL, 2, 1, { NULL, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member } }, - [0x4f] = { "SetMember", NULL }, /* apparently the result is ignored */ + [0x4f] = { "SetMember", NULL, 3, 0, { NULL, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member } }, [0x50] = { "Increment", NULL }, [0x51] = { "Decrement", NULL }, [0x52] = { "CallMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_call_method, swfdec_action_call_method, swfdec_action_call_method } }, diff-tree 756c3c6c257d890fd5b35221ab7451017bb56d03 (from 469151c6400bd4dde8b9e0356274bbec5f105c4b) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 19:34:22 2007 +0100 implement GetMember and Add2 for Flash7 30/44 failures diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index b8d3dc6..8f073b7 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -500,6 +500,69 @@ out: return JS_TRUE; } +static JSBool +swfdec_action_add2_7 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval rval, lval; + gboolean cond; + + rval = cx->fp->sp[-1]; + lval = cx->fp->sp[-2]; + if (!JSVAL_IS_PRIMITIVE (rval)) { + if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT (rval), 0 , &rval)) + return JS_FALSE; + } + if (!JSVAL_IS_PRIMITIVE (lval)) { + if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT (lval), 0 , &lval)) + return JS_FALSE; + } + if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) { + JSString *str, *str2; + if (cond) { + str = JSVAL_TO_STRING (lval); + if ((str2 = js_ValueToString (cx, rval)) != NULL) + return JS_FALSE; + } else { + str2 = JSVAL_TO_STRING (rval); + if ((str = js_ValueToString (cx, lval)) != NULL) + return JS_FALSE; + } + str = js_ConcatStrings (cx, str, str2); + if (!str) + return JS_FALSE; + cx->fp->sp--; + cx->fp->sp[-1] = STRING_TO_JSVAL (str); + } else { + double d, d2; + if (!JS_ValueToNumber(cx, lval, &d) || + !JS_ValueToNumber(cx, rval, &d2)) + return JS_FALSE; + d += d2; + cx->fp->sp--; + return JS_NewDoubleValue(cx, d, &cx->fp->sp[-1]); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_get_member (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *s; + + s = swfdec_js_to_string (cx, cx->fp->sp[-1]); + if (s == NULL) + return JS_FALSE; + + if (JSVAL_IS_OBJECT (cx->fp->sp[-2])) { + if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-2]), s, &cx->fp->sp[-2])) + return JS_FALSE; + } else { + cx->fp->sp[-2] = JSVAL_VOID; + } + cx->fp->sp--; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -685,14 +748,14 @@ static const SwfdecActionSpec actions[25 [0x44] = { "Typeof", NULL }, [0x45] = { "TargetPath", NULL }, [0x46] = { "Enumerate", NULL }, - [0x47] = { "Add2", NULL }, + [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, NULL, NULL, swfdec_action_add2_7 } }, [0x48] = { "Less2", NULL }, [0x49] = { "Equals2", NULL }, [0x4a] = { "ToNumber", NULL }, [0x4b] = { "ToString", NULL }, [0x4c] = { "PushDuplicate", NULL }, [0x4d] = { "Swap", NULL }, - [0x4e] = { "GetMember", NULL }, + [0x4e] = { "GetMember", NULL, 2, 1, { NULL, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member } }, [0x4f] = { "SetMember", NULL }, /* apparently the result is ignored */ [0x50] = { "Increment", NULL }, [0x51] = { "Decrement", NULL }, diff-tree 469151c6400bd4dde8b9e0356274bbec5f105c4b (from 1df9fa9d227af58658f4c2b9bf1e9a6719c4d9dc) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 13:27:27 2007 +0100 add GetProperty and SetProperty actions 32/44 failures now diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index e688089..b8d3dc6 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -410,6 +410,96 @@ swfdec_action_pop (JSContext *cx, guint return JS_TRUE; } +static const char *properties[22] = { + "_x", "_y", "_xscale", "_yscale", "_currentframe", + "_totalframes", "_alpha", "_visible", "_width", "_height", + "_rotation", "_target", "_framesloaded", "_name", "_droptarget", + "_url", "_highquality", "_focusrect", "_soundbuftime", "_quality", + "_xmouse", "_ymouse" +}; + +static JSBool +swfdec_eval_jsval (JSContext *cx, JSObject *obj, jsval *val) +{ + if (JSVAL_IS_STRING (*val)) { + const char *bytes = swfdec_js_to_string (cx, *val); + if (bytes == NULL) + return JS_FALSE; + *val = swfdec_js_eval (cx, obj, bytes); + } else { + SWFDEC_ERROR ("huh?"); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_get_property (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval val; + SwfdecMovie *movie; + JSObject *jsobj; + guint32 id; + + val = cx->fp->sp[-2]; + if (!swfdec_eval_jsval (cx, cx->fp->scopeChain, &val)) + return JS_FALSE; + movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE); + val = JSVAL_VOID; + if (movie == NULL) { + SWFDEC_WARNING ("specified target does not reference a movie clip"); + goto out; + } + if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &id)) + return JS_FALSE; + + if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) + goto out; + + if (!(jsobj = swfdec_scriptable_get_object (SWFDEC_SCRIPTABLE (movie)))) + return JS_FALSE; + + if (!JS_GetProperty (cx, jsobj, properties[id], &val)) + return JS_FALSE; + +out: + cx->fp->sp -= 1; + cx->fp->sp[-1] = val; + return JS_TRUE; +} + +static JSBool +swfdec_action_set_property (JSContext *cx, guint action, const guint8 *data, guint len) +{ + jsval val; + SwfdecMovie *movie; + JSObject *jsobj; + guint32 id; + + val = cx->fp->sp[-2]; + if (!swfdec_eval_jsval (cx, cx->fp->scopeChain, &val)) + return JS_FALSE; + movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE); + if (movie == NULL) { + SWFDEC_WARNING ("specified target does not reference a movie clip"); + goto out; + } + if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &id)) + return JS_FALSE; + + if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) + goto out; + + if (!(jsobj = swfdec_scriptable_get_object (SWFDEC_SCRIPTABLE (movie)))) + return JS_FALSE; + + if (!JS_SetProperty (cx, jsobj, properties[id], &cx->fp->sp[-3])) + return JS_FALSE; + +out: + cx->fp->sp -= 3; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -560,8 +650,8 @@ static const SwfdecActionSpec actions[25 [0x1d] = { "SetVariable", NULL }, [0x20] = { "SetTarget2", NULL }, [0x21] = { "StringAdd", NULL }, - [0x22] = { "GetProperty", NULL }, - [0x23] = { "SetProperty", NULL }, + [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } }, + [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } }, [0x24] = { "CloneSprite", NULL }, [0x25] = { "RemoveSprite", NULL }, [0x26] = { "Trace", NULL, 1, 0, { NULL, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace } }, diff-tree 1df9fa9d227af58658f4c2b9bf1e9a6719c4d9dc (from 1fbe061229c9be6b6374f95fc0e70a786e8a33d5) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 13:27:05 2007 +0100 add stub for _quality property diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c index f5bf871..70ddece 100644 --- a/libswfdec/swfdec_js_movie.c +++ b/libswfdec/swfdec_js_movie.c @@ -1056,6 +1056,7 @@ static JSPropertySpec movieclip_props[] {"_highquality", -1, MC_PROP_ATTRS, not_reached, not_reached }, {"_focusrect", -1, MC_PROP_ATTRS, not_reached, not_reached }, {"_soundbuftime", -1, MC_PROP_ATTRS, not_reached, not_reached }, + {"_quality", -1, MC_PROP_ATTRS, not_reached, not_reached }, {"_xmouse", -1, MC_PROP_ATTRS, not_reached, not_reached }, {"_ymouse", -1, MC_PROP_ATTRS, not_reached, not_reached }, {"_parent", -1, MC_PROP_ATTRS | JSPROP_READONLY, mc_parent, NULL}, diff-tree 1fbe061229c9be6b6374f95fc0e70a786e8a33d5 (from 5f777f6697273122587f8bcf645e3a81a7f77228) Author: Benjamin Otte <otte@gnome.org> Date: Fri Jan 19 12:53:56 2007 +0100 implement CallMethod and Pop + lots of bugfixing after this commit, test/trace has 33/44 failures diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index ed5ac44..e688089 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -304,7 +304,7 @@ swfdec_action_push (JSContext *cx, guint return JS_FALSE; } } - return swfdec_bits_left (&bits) ? JS_TRUE : JS_FALSE; + return swfdec_bits_left (&bits) ? JS_FALSE : JS_TRUE; } static JSBool @@ -326,6 +326,7 @@ swfdec_action_trace (JSContext *cx, guin const char *bytes; bytes = swfdec_js_to_string (cx, cx->fp->sp[-1]); + cx->fp->sp--; if (bytes == NULL) return JS_TRUE; @@ -333,6 +334,82 @@ swfdec_action_trace (JSContext *cx, guin return JS_TRUE; } +/** + * swfdec_action_invoke: + * @cx: the #JSContext + * @n_args: number of arguments + * + * This function is similar to js_Invoke, however it uses a reversed stack + * order. sp[-1] has to be the function to call, sp[-2] will be the object the + * function is called on, sp[-3] is the first argument, followed by the rest of + * the arguments. The function reorders the stack on success and pushes the + * return value on top. + * + * Returns: JS_TRUE on success, JS_FALSE on failure. + **/ +static JSBool +swfdec_action_call (JSContext *cx, guint n_args, guint flags) +{ + int i, j; + jsval tmp; + + j = -1; + i = - (n_args + 2); + while (i < j) { + tmp = cx->fp->sp[j]; + cx->fp->sp[j] = cx->fp->sp[i]; + cx->fp->sp[i] = tmp; + j--; + i++; + } + return js_Invoke (cx, n_args, flags); +} + +static JSBool +swfdec_action_call_method (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSStackFrame *fp = cx->fp; + const char *s; + guint32 n_args; + JSObject *obj; + jsval fun; + + s = swfdec_js_to_string (cx, fp->sp[-1]); + if (s == NULL) + return JS_FALSE; + if (!JS_ValueToECMAUint32 (cx, fp->sp[-3], &n_args)) + return JS_FALSE; + if (n_args + 3 > (guint) (fp->sp - fp->spbase)) + return JS_FALSE; + + if (!JSVAL_IS_OBJECT (fp->sp[-2])) + goto fail; + obj = JSVAL_TO_OBJECT (fp->sp[-2]); + if (s[0] == '\0') { + fun = OBJECT_TO_JSVAL (obj); + } else { + if (!JS_GetProperty (cx, obj, s, &fun)) + return JS_FALSE; + } + fp->sp--; + fp->sp[-1] = fun; + fp->sp[-2] = OBJECT_TO_JSVAL (obj); + swfdec_action_call (cx, n_args, 0); + return JS_TRUE; + +fail: + fp->sp -= 2 + n_args; + fp->sp[-1] = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool +swfdec_action_pop (JSContext *cx, guint action, const guint8 *data, guint len) +{ + cx->fp->sp--; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -477,7 +554,7 @@ static const SwfdecActionSpec actions[25 [0x13] = { "StringEquals", NULL }, [0x14] = { "StringLength", NULL }, [0x15] = { "StringExtract", NULL }, - [0x17] = { "Pop", NULL }, + [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } }, [0x18] = { "ToInteger", NULL }, [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, [0x1d] = { "SetVariable", NULL }, @@ -529,7 +606,7 @@ static const SwfdecActionSpec actions[25 [0x4f] = { "SetMember", NULL }, /* apparently the result is ignored */ [0x50] = { "Increment", NULL }, [0x51] = { "Decrement", NULL }, - [0x52] = { "CallMethod", NULL }, + [0x52] = { "CallMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_call_method, swfdec_action_call_method, swfdec_action_call_method } }, [0x53] = { "NewMethod", NULL }, /* version 6 */ [0x54] = { "InstanceOf", NULL }, @@ -726,7 +803,7 @@ swfdec_script_interpret (SwfdecScript *s guint8 *startpc, *pc, *endpc, *nextpc; JSBool ok = JS_TRUE; void *mark; - jsval *startsp, *endsp; + jsval *startsp, *endsp, *checksp; int stack_check; guint action, len; guint8 *data; @@ -800,6 +877,8 @@ swfdec_script_interpret (SwfdecScript *s goto internal_error; } if (spec->add < 0) { + /* HACK FIXME: if added args are -1, we pass the number of free space on the stack + * instead of the action */ action = endsp - fp->sp; } else { if (fp->sp + spec->add - MAX (spec->remove, 0) > endsp) { @@ -807,9 +886,18 @@ swfdec_script_interpret (SwfdecScript *s goto internal_error; } } + checksp = (spec->add >= 0 && spec->remove >= 0) ? fp->sp + spec->add - spec->remove : NULL; ok = spec->exec[version] (cx, action, data, len); - if (!ok) + if (!ok) { + SWFDEC_WARNING ("action %s failed", spec->name); goto out; + } + if (checksp != NULL && checksp != fp->sp) { + /* check stack was handled like expected */ + g_error ("action %s was supposed to change the stack by %d (+%d -%d), but it changed by %d", + spec->name, spec->add - spec->remove, spec->add, spec->remove, + fp->sp - checksp + spec->add - spec->remove); + } if (fp->pc == pc) { fp->pc = pc = nextpc; } else { diff-tree 5f777f6697273122587f8bcf645e3a81a7f77228 (from 878ec656b0711cd19c11554d0617109a058af799) Author: Benjamin Otte <otte@gnome.org> Date: Thu Jan 18 18:15:51 2007 +0100 implement Trace action includes changing the API to have a swfdec_player_trace function diff --git a/libswfdec/swfdec_js_global.c b/libswfdec/swfdec_js_global.c index daa8f75..328d74d 100644 --- a/libswfdec/swfdec_js_global.c +++ b/libswfdec/swfdec_js_global.c @@ -50,8 +50,7 @@ swfdec_js_trace (JSContext *cx, JSObject if (bytes == NULL) return JS_TRUE; - /* FIXME: accumulate and emit after JS handling? */ - g_signal_emit_by_name (player, "trace", bytes); + swfdec_player_trace (player, bytes); return JS_TRUE; } diff --git a/libswfdec/swfdec_player.c b/libswfdec/swfdec_player.c index 811e7c6..4b29d28 100644 --- a/libswfdec/swfdec_player.c +++ b/libswfdec/swfdec_player.c @@ -837,6 +837,16 @@ swfdec_player_stop_all_sounds (SwfdecPla } void +swfdec_player_trace (SwfdecPlayer *player, const char *text) +{ + g_return_if_fail (SWFDEC_IS_PLAYER (player)); + g_return_if_fail (text != NULL); + + /* FIXME: accumulate and emit after JS handling? */ + g_signal_emit (player, signals[TRACE], 0, text); +} + +void swfdec_player_invalidate (SwfdecPlayer *player, const SwfdecRect *rect) { if (swfdec_rect_is_empty (rect)) { diff --git a/libswfdec/swfdec_player_internal.h b/libswfdec/swfdec_player_internal.h index dd10949..2da8ecc 100644 --- a/libswfdec/swfdec_player_internal.h +++ b/libswfdec/swfdec_player_internal.h @@ -122,6 +122,8 @@ void swfdec_player_set_drag_movie (Swfd SwfdecMovie * drag, gboolean center, SwfdecRect * rect); +void swfdec_player_trace (SwfdecPlayer * player, + const char * text); void swfdec_player_stop_all_sounds (SwfdecPlayer * player); SwfdecRootMovie * swfdec_player_add_level_from_loader (SwfdecPlayer * player, diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 49ad92f..ed5ac44 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -31,6 +31,7 @@ #include "swfdec_decoder.h" #include "swfdec_js.h" #include "swfdec_movie.h" +#include "swfdec_player_internal.h" #include "swfdec_root_movie.h" /*** CONSTANT POOLS ***/ @@ -318,6 +319,20 @@ swfdec_action_get_variable (JSContext *c return JS_TRUE; } +static JSBool +swfdec_action_trace (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecPlayer *player = JS_GetContextPrivate (cx); + const char *bytes; + + bytes = swfdec_js_to_string (cx, cx->fp->sp[-1]); + if (bytes == NULL) + return JS_TRUE; + + swfdec_player_trace (player, bytes); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -472,7 +487,7 @@ static const SwfdecActionSpec actions[25 [0x23] = { "SetProperty", NULL }, [0x24] = { "CloneSprite", NULL }, [0x25] = { "RemoveSprite", NULL }, - [0x26] = { "Trace", NULL }, + [0x26] = { "Trace", NULL, 1, 0, { NULL, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace } }, [0x27] = { "StartDrag", NULL }, [0x28] = { "EndDrag", NULL }, [0x29] = { "StringLess", NULL }, diff-tree 878ec656b0711cd19c11554d0617109a058af799 (from 8a1b77a18b9266e33c5e92ebeb0a8edbb7b6e643) Author: Benjamin Otte <otte@gnome.org> Date: Thu Jan 18 15:05:37 2007 +0100 implement GetVariable, fix a missing break in print_push and add better debugging diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index a27f037..49ad92f 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -29,6 +29,7 @@ #include <string.h> #include "swfdec_decoder.h" +#include "swfdec_js.h" #include "swfdec_movie.h" #include "swfdec_root_movie.h" @@ -305,6 +306,18 @@ swfdec_action_push (JSContext *cx, guint return swfdec_bits_left (&bits) ? JS_TRUE : JS_FALSE; } +static JSBool +swfdec_action_get_variable (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *s; + + s = swfdec_js_to_string (cx, cx->fp->sp[-1]); + if (s == NULL) + return JS_FALSE; + cx->fp->sp[-1] = swfdec_js_eval (cx, cx->fp->scopeChain, s); + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -352,6 +365,7 @@ swfdec_action_print_push (guint action, break; case 7: /* 32bit int */ g_string_append_printf (string, "%u", swfdec_bits_get_u32 (&bits)); + break; case 8: /* 8bit ConstantPool address */ g_string_append_printf (string, "Pool %u", swfdec_bits_get_u8 (&bits)); break; @@ -450,7 +464,7 @@ static const SwfdecActionSpec actions[25 [0x15] = { "StringExtract", NULL }, [0x17] = { "Pop", NULL }, [0x18] = { "ToInteger", NULL }, - [0x1c] = { "GetVariable", NULL }, + [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, [0x1d] = { "SetVariable", NULL }, [0x20] = { "SetTarget2", NULL }, [0x21] = { "StringAdd", NULL }, @@ -604,8 +618,9 @@ validate_action (guint action, const gui /* ensure there's a function to execute this opcode, otherwise fail */ if (actions[action].exec[version] == NULL) { - SWFDEC_ERROR ("no opcode for %u %s", action, - actions[action].name ? actions[action].name : "Unknown"); + SWFDEC_ERROR ("no function for %u %s in v%u", action, + actions[action].name ? actions[action].name : "Unknown", + script->version); return FALSE; } /* we might want to do stuff here for certain actions */ diff-tree 8a1b77a18b9266e33c5e92ebeb0a8edbb7b6e643 (from c41b8582293535b64bf83c19843bd4eae8662e6f) Author: Benjamin Otte <otte@gnome.org> Date: Thu Jan 18 12:52:36 2007 +0100 implement ConstantPool and Push diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 5b01510..a27f037 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -27,18 +27,86 @@ #include "js/jscntxt.h" #include "js/jsinterp.h" -/*** SUPPORT FUNCTIONS ***/ - +#include <string.h> #include "swfdec_decoder.h" #include "swfdec_movie.h" #include "swfdec_root_movie.h" +/*** CONSTANT POOLS ***/ + +typedef GPtrArray SwfdecConstantPool; + +static SwfdecConstantPool * +swfdec_constant_pool_new_from_action (const guint8 *data, guint len) +{ + guint8 *next; + guint i, n; + GPtrArray *pool; + + if (len < 2) { + SWFDEC_ERROR ("constant pool too small"); + return NULL; + } + n = GUINT16_FROM_LE (*((guint16*) data)); + data += 2; + len -= 2; + pool = g_ptr_array_sized_new (n); + g_ptr_array_set_size (pool, n); + for (i = 0; i < n; i++) { + next = memchr (data, 0, len); + if (next == NULL) { + SWFDEC_ERROR ("not enough strings available"); + g_ptr_array_free (pool, TRUE); + return NULL; + } + next++; + g_ptr_array_index (pool, i) = (gpointer) data; + len -= next - data; + data = next; + } + if (len != 0) { + SWFDEC_WARNING ("constant pool didn't consume whole buffer (%u bytes leftover)", len); + } + return pool; +} + +static guint +swfdec_constant_pool_size (SwfdecConstantPool *pool) +{ + return pool->len; +} + +static const char * +swfdec_constant_pool_get (SwfdecConstantPool *pool, guint i) +{ + g_assert (i < pool->len); + return g_ptr_array_index (pool, i); +} + +static void +swfdec_constant_pool_free (SwfdecConstantPool *pool) +{ + g_ptr_array_free (pool, TRUE); +} + +/*** SUPPORT FUNCTIONS ***/ + static SwfdecMovie * swfdec_action_get_target (JSContext *cx) { return swfdec_scriptable_from_jsval (cx, OBJECT_TO_JSVAL (cx->fp->scopeChain), SWFDEC_TYPE_MOVIE); } +static JSBool +swfdec_action_push_string (JSContext *cx, const char *s) +{ + JSString *string = JS_NewStringCopyZ (cx, s); + if (string == NULL) + return JS_FALSE; + *cx->fp->sp++ = STRING_TO_JSVAL (string); + return JS_TRUE; +} + /*** ALL THE ACTION IS HERE ***/ static JSBool @@ -130,9 +198,194 @@ swfdec_action_wait_for_frame (JSContext return JS_TRUE; } +static JSBool +swfdec_action_constant_pool (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecConstantPool *pool; + + pool = swfdec_constant_pool_new_from_action (data, len); + if (pool == NULL) + return JS_FALSE; + if (cx->fp->constant_pool) + swfdec_constant_pool_free (cx->fp->constant_pool); + cx->fp->constant_pool = pool; + return JS_TRUE; +} + +static JSBool +swfdec_action_push (JSContext *cx, guint stackspace, const guint8 *data, guint len) +{ + /* FIXME: supply API for this */ + SwfdecBits bits; + + swfdec_bits_init_data (&bits, data, len); + while (swfdec_bits_left (&bits) && stackspace-- > 0) { + guint type = swfdec_bits_get_u8 (&bits); + SWFDEC_LOG ("push type %u", type); + switch (type) { + case 0: /* string */ + { + const char *s = swfdec_bits_skip_string (&bits); + if (!swfdec_action_push_string (cx, s)) + return JS_FALSE; + break; + } + case 1: /* float */ + { + double d = swfdec_bits_get_float (&bits); + if (!JS_NewDoubleValue (cx, d, cx->fp->sp)) + return JS_FALSE; + cx->fp->sp++; + break; + } + case 2: /* null */ + *cx->fp->sp++ = JSVAL_NULL; + break; + case 3: /* undefined */ + *cx->fp->sp++ = JSVAL_VOID; + break; + case 5: /* boolean */ + *cx->fp->sp++ = swfdec_bits_get_u8 (&bits) ? JSVAL_TRUE : JSVAL_FALSE; + break; + case 6: /* double */ + { + double d = swfdec_bits_get_float (&bits); + if (!JS_NewDoubleValue (cx, d, cx->fp->sp)) + return JS_FALSE; + cx->fp->sp++; + break; + } + case 7: /* 32bit int */ + { + /* FIXME: spec says U32, do they mean this? */ + guint i = swfdec_bits_get_u32 (&bits); + *cx->fp->sp++ = INT_TO_JSVAL (i); + break; + } + case 8: /* 8bit ConstantPool address */ + { + guint i = swfdec_bits_get_u8 (&bits); + SwfdecConstantPool *pool = cx->fp->constant_pool; + if (pool == NULL) { + SWFDEC_ERROR ("no constant pool to push from"); + return JS_FALSE; + } + if (i >= swfdec_constant_pool_size (pool)) { + SWFDEC_ERROR ("constant pool index %u too high - only %u elements", + i, swfdec_constant_pool_size (pool)); + return JS_FALSE; + } + if (!swfdec_action_push_string (cx, swfdec_constant_pool_get (pool, i))) + return JS_FALSE; + break; + } + case 9: /* 16bit ConstantPool address */ + { + guint i = swfdec_bits_get_u16 (&bits); + SwfdecConstantPool *pool = cx->fp->constant_pool; + if (pool == NULL) { + SWFDEC_ERROR ("no constant pool to push from"); + return JS_FALSE; + } + if (i >= swfdec_constant_pool_size (pool)) { + SWFDEC_ERROR ("constant pool index %u too high - only %u elements", + i, swfdec_constant_pool_size (pool)); + return JS_FALSE; + } + if (!swfdec_action_push_string (cx, swfdec_constant_pool_get (pool, i))) + return JS_FALSE; + break; + } + case 4: /* register */ + default: + SWFDEC_ERROR ("Push: type %u not implemented", type); + return JS_FALSE; + } + } + return swfdec_bits_left (&bits) ? JS_TRUE : JS_FALSE; +} + /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_push (guint action, const guint8 *data, guint len) +{ + gboolean first = TRUE; + SwfdecBits bits; + GString *string = g_string_new ("Push"); + + swfdec_bits_init_data (&bits, data, len); + while (swfdec_bits_left (&bits)) { + guint type = swfdec_bits_get_u8 (&bits); + if (first) + g_string_append (string, " "); + else + g_string_append (string, ", "); + first = FALSE; + switch (type) { + case 0: /* string */ + { + const char *s = swfdec_bits_skip_string (&bits); + if (!s) { + g_string_free (string, TRUE); + return NULL; + } + g_string_append_c (string, '"'); + g_string_append (string, s); + g_string_append_c (string, '"'); + break; + } + case 1: /* float */ + g_string_append_printf (string, "%g", swfdec_bits_get_float (&bits)); + break; + case 2: /* null */ + g_string_append (string, "null"); + break; + case 3: /* undefined */ + g_string_append (string, "void"); + break; + case 5: /* boolean */ + g_string_append (string, swfdec_bits_get_u8 (&bits) ? "True" : "False"); + break; + case 6: /* double */ + g_string_append_printf (string, "%g", swfdec_bits_get_double (&bits)); + break; + case 7: /* 32bit int */ + g_string_append_printf (string, "%u", swfdec_bits_get_u32 (&bits)); + case 8: /* 8bit ConstantPool address */ + g_string_append_printf (string, "Pool %u", swfdec_bits_get_u8 (&bits)); + break; + case 9: /* 16bit ConstantPool address */ + g_string_append_printf (string, "Pool %u", swfdec_bits_get_u16 (&bits)); + break; + case 4: /* register */ + default: + SWFDEC_ERROR ("Push: type %u not implemented", type); + return JS_FALSE; + } + } + return g_string_free (string, FALSE); +} + +static char * +swfdec_action_print_constant_pool (guint action, const guint8 *data, guint len) +{ + guint i; + GString *string; + SwfdecConstantPool *pool; + + pool = swfdec_constant_pool_new_from_action (data, len); + if (pool == NULL) + return JS_FALSE; + string = g_string_new ("ConstantPool"); + for (i = 0; i < swfdec_constant_pool_size (pool); i++) { + g_string_append (string, i ? ", " : " "); + g_string_append (string, swfdec_constant_pool_get (pool, i)); + } + return g_string_free (string, FALSE); +} + +static char * swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len) { guint frame; @@ -162,13 +415,14 @@ swfdec_action_print_wait_for_frame (guin /* defines minimum and maximum versions for which we have seperate scripts */ #define MINSCRIPTVERSION 3 #define MAXSCRIPTVERSION 7 +#define EXTRACT_VERSION(v) MAX ((v) - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION) typedef JSBool (* SwfdecActionExec) (JSContext *cx, guint action, const guint8 *data, guint len); typedef struct { const char * name; /* name identifying the action */ char * (* print) (guint action, const guint8 *data, guint len); int remove; /* values removed from stack or -1 for dynamic */ - guint add; /* values added to the stack */ + int add; /* values added to the stack or -1 for dynamic */ SwfdecActionExec exec[MAXSCRIPTVERSION - MINSCRIPTVERSION + 1]; /* array is for version 3, 4, 5, 6, 7+ */ } SwfdecActionSpec; @@ -270,7 +524,7 @@ static const SwfdecActionSpec actions[25 [0x83] = { "GetURL", NULL }, /* version 5 */ [0x87] = { "StoreRegister", NULL }, - [0x88] = { "ConstantPool", NULL }, + [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } }, /* version 3 */ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, [0x8b] = { "SetTarget", NULL }, @@ -283,7 +537,7 @@ static const SwfdecActionSpec actions[25 /* version 5 */ [0x94] = { "With", NULL }, /* version 4 */ - [0x96] = { "Push", NULL }, + [0x96] = { "Push", swfdec_action_print_push, 0, -1, { NULL, swfdec_action_push, swfdec_action_push, swfdec_action_push, swfdec_action_push } }, [0x99] = { "Jump", NULL }, [0x9a] = { "GetURL2", NULL }, /* version 5 */ @@ -320,7 +574,7 @@ static gboolean swfdec_script_foreach (SwfdecBits *bits, SwfdecScriptForeachFunc func, gpointer user_data) { guint action, len; - guint8 *data; + const guint8 *data; while ((action = swfdec_bits_get_u8 (bits))) { if (action & 0x80) { @@ -343,10 +597,19 @@ swfdec_script_foreach (SwfdecBits *bits, /*** PUBLIC API ***/ static gboolean -validate_action (guint action, const guint8 *data, guint len, gpointer script) +validate_action (guint action, const guint8 *data, guint len, gpointer scriptp) { + SwfdecScript *script = scriptp; + int version = EXTRACT_VERSION (script->version); + + /* ensure there's a function to execute this opcode, otherwise fail */ + if (actions[action].exec[version] == NULL) { + SWFDEC_ERROR ("no opcode for %u %s", action, + actions[action].name ? actions[action].name : "Unknown"); + return FALSE; + } /* we might want to do stuff here for certain actions */ -#if 0 +#if 1 { char *foo = swfdec_script_print_action (action, data, len); if (foo == NULL) @@ -361,7 +624,7 @@ SwfdecScript * swfdec_script_new (SwfdecBits *bits, const char *name, unsigned int version) { SwfdecScript *script; - guchar *start; + const guchar *start; g_return_val_if_fail (bits != NULL, NULL); if (version < MINSCRIPTVERSION) { @@ -442,7 +705,7 @@ swfdec_script_interpret (SwfdecScript *s /* set up general stuff */ swfdec_script_ref (script); - version = MAX (script->version - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION); + version = EXTRACT_VERSION (script->version); *rval = JSVAL_VOID; fp = cx->fp; /* set up the script */ @@ -506,9 +769,13 @@ swfdec_script_interpret (SwfdecScript *s spec->name, spec->remove, fp->sp - fp->spbase); goto internal_error; } - if (fp->sp + spec->add - MAX (spec->remove, 0) > endsp) { - SWFDEC_ERROR ("FIXME: implement stack expansion, we got an overflow"); - goto internal_error; + if (spec->add < 0) { + action = endsp - fp->sp; + } else { + if (fp->sp + spec->add - MAX (spec->remove, 0) > endsp) { + SWFDEC_ERROR ("FIXME: implement stack expansion, we got an overflow"); + goto internal_error; + } } ok = spec->exec[version] (cx, action, data, len); if (!ok) @@ -574,6 +841,7 @@ swfdec_script_execute (SwfdecScript *scr frame.varobj = obj; frame.fun = NULL; frame.swf = script; + frame.constant_pool = NULL; frame.thisp = obj; frame.argc = frame.nvars = 0; frame.argv = frame.vars = NULL; @@ -604,6 +872,10 @@ swfdec_script_execute (SwfdecScript *scr */ ok = swfdec_script_interpret (script, cx, &frame.rval); + /* FIXME: where to clean this up? */ + if (frame.constant_pool) + swfdec_constant_pool_free (frame.constant_pool); + cx->fp = oldfp; if (oldfp) { g_assert (cx->dormantFrameChain == oldfp); diff-tree c41b8582293535b64bf83c19843bd4eae8662e6f (from 539f1f3151a6deb4f231f3289d3c8c232eb21bc7) Author: Benjamin Otte <otte@gnome.org> Date: Thu Jan 18 12:51:56 2007 +0100 add the constant pool to the stack frame diff --git a/libswfdec/js/jsinterp.h b/libswfdec/js/jsinterp.h index b22166d..88bab68 100644 --- a/libswfdec/js/jsinterp.h +++ b/libswfdec/js/jsinterp.h @@ -56,6 +56,7 @@ struct JSStackFrame { JSObject *varobj; /* variables object, where vars go */ JSScript *script; /* script being interpreted or NULL */ void *swf; /* SwfdecScript being executed if script is NULL */ + void *constant_pool; /* constant pool used by SwfdecScript */ JSFunction *fun; /* function being called or null */ JSObject *thisp; /* "this" pointer if in method */ uintN argc; /* actual argument count */ diff-tree 539f1f3151a6deb4f231f3289d3c8c232eb21bc7 (from c3f0eaf5706a0d972132a0ea4fcaff5aa79ec122) Author: Benjamin Otte <otte@gnome.org> Date: Thu Jan 18 12:47:17 2007 +0100 implement swfdec_bits_init_from_data to use SwfdecBits without a buffer Also make bits.ptr and bits.end const variables. This required cleaning up lots of old code that still accessed SwfdecBits directly I bet there were a lot of security issues there ;) diff --git a/libswfdec/swfdec_bits.c b/libswfdec/swfdec_bits.c index f9f2749..72cc3df 100644 --- a/libswfdec/swfdec_bits.c +++ b/libswfdec/swfdec_bits.c @@ -43,6 +43,27 @@ swfdec_bits_init (SwfdecBits *bits, Swfd bits->end = buffer->data + buffer->length; } +/** + * swfdec_bits_init_data: + * @bits: the #SwfdecBits to initialize + * @data: data to initialize with + * @len: length of the data + * + * Initializes @bits for use with the given @data. All operations on @bits will + * return copies of the data, so after use, you can free the supplied data. + **/ +void +swfdec_bits_init_data (SwfdecBits *bits, const guint8 *data, guint len) +{ + g_return_if_fail (bits != NULL); + g_return_if_fail (data != NULL); + + bits->buffer = NULL; + bits->ptr = data; + bits->idx = 0; + bits->end = bits->ptr + len; +} + unsigned int swfdec_bits_left (SwfdecBits *b) { @@ -557,7 +578,12 @@ swfdec_bits_get_buffer (SwfdecBits *bits if (len == 0) return NULL; } - buffer = swfdec_buffer_new_subbuffer (bits->buffer, bits->ptr - bits->buffer->data, len); + if (bits->buffer) { + buffer = swfdec_buffer_new_subbuffer (bits->buffer, bits->ptr - bits->buffer->data, len); + } else { + buffer = swfdec_buffer_new_and_alloc (len); + memcpy (buffer->data, bits->ptr, len); + } bits->ptr += len; return buffer; } diff --git a/libswfdec/swfdec_bits.h b/libswfdec/swfdec_bits.h index 86440f7..08ae1d8 100644 --- a/libswfdec/swfdec_bits.h +++ b/libswfdec/swfdec_bits.h @@ -32,13 +32,14 @@ typedef struct _SwfdecBits SwfdecBits; struct _SwfdecBits { - SwfdecBuffer *buffer; - unsigned char *ptr; - unsigned int idx; - unsigned char *end; + SwfdecBuffer * buffer; /* buffer data is taken from or NULL */ + const unsigned char * ptr; /* current location to read from */ + unsigned int idx; /* bits already read from ptr */ + const unsigned char * end; /* pointer after last byte */ }; void swfdec_bits_init (SwfdecBits *bits, SwfdecBuffer *buffer); +void swfdec_bits_init_data (SwfdecBits *bits, const guint8 *data, guint len); unsigned int swfdec_bits_left (SwfdecBits *b); int swfdec_bits_getbit (SwfdecBits * b); unsigned int swfdec_bits_getbits (SwfdecBits * b, unsigned int n); diff --git a/libswfdec/swfdec_codec_screen.c b/libswfdec/swfdec_codec_screen.c index 305db49..de21d21 100644 --- a/libswfdec/swfdec_codec_screen.c +++ b/libswfdec/swfdec_codec_screen.c @@ -140,7 +140,7 @@ swfdec_codec_screen_decode (gpointer cod if (inflateReset(&screen->z) != Z_OK) { SWFDEC_ERROR ("error resetting zlib decoder: %s", screen->z.msg); } - screen->z.next_in = bits.ptr; + screen->z.next_in = (void *) bits.ptr; if (swfdec_bits_skip_bytes (&bits, size) != size) { SWFDEC_ERROR ("not enough bytes available"); return NULL; diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index 6c2dcae..c9df0de 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -99,46 +99,30 @@ zfree (void *opaque, void *addr) g_free (addr); } -static void * -lossless (void *zptr, int zlen, int *plen) +static guint8 * +lossless (const guint8 *zptr, int zlen, int len) { - void *data; - int len; - z_stream *z; + guint8 *data; + z_stream z = { NULL, }; int ret; - z = g_new0 (z_stream, 1); - z->zalloc = zalloc; - z->zfree = zfree; - z->opaque = NULL; - - z->next_in = zptr; - z->avail_in = zlen; - - data = NULL; - len = 0; - ret = inflateInit (z); - while (z->avail_in > 0) { - if (z->avail_out == 0) { - len += 1024; - data = g_realloc (data, len); - z->next_out = data + z->total_out; - z->avail_out += 1024; - } - ret = inflate (z, Z_SYNC_FLUSH); - if (ret != Z_OK) - break; - } + z.zalloc = zalloc; + z.zfree = zfree; + z.opaque = NULL; + + data = g_malloc (len); + z.next_in = (Bytef *) zptr; + z.avail_in = zlen; + z.next_out = data; + z.avail_out = len; + + ret = inflateInit (&z); + ret = inflate (&z, Z_SYNC_FLUSH); if (ret != Z_STREAM_END) { SWFDEC_WARNING ("lossless: ret == %d", ret); } + inflateEnd (&z); - if (plen) - (*plen) = z->total_out; - - inflateEnd (z); - - g_free (z); return data; } @@ -278,11 +262,8 @@ int tag_func_define_bits_jpeg_3 (SwfdecSwfDecoder * s) { SwfdecBits *bits = &s->b; - int id; + guint id; SwfdecImage *image; - unsigned char *endptr; - - endptr = bits->ptr + bits->buffer->length; id = swfdec_bits_get_u16 (bits); SWFDEC_LOG (" id = %d", id); @@ -292,9 +273,7 @@ tag_func_define_bits_jpeg_3 (SwfdecSwfDe return SWFDEC_STATUS_OK; image->type = SWFDEC_IMAGE_TYPE_JPEG3; - image->raw_data = swfdec_buffer_ref (bits->buffer); - - bits->ptr += bits->buffer->length - 2; + image->raw_data = swfdec_bits_get_buffer (bits, -1); return SWFDEC_STATUS_OK; } @@ -306,21 +285,20 @@ swfdec_image_jpeg3_load (SwfdecImage *im unsigned char *image_data; unsigned char *alpha_data; SwfdecBits bits; - int len; + SwfdecBuffer *buffer; int jpeg_length; - bits.buffer = image->raw_data; - bits.ptr = image->raw_data->data; - bits.idx = 0; - bits.end = bits.ptr + image->raw_data->length; - - bits.ptr += 2; + swfdec_bits_init (&bits, image->raw_data); jpeg_length = swfdec_bits_get_u32 (&bits); + buffer = swfdec_bits_get_buffer (&bits, jpeg_length); + if (buffer == NULL) + return; dec = jpeg_rgb_decoder_new (); - jpeg_rgb_decoder_addbits (dec, bits.ptr, jpeg_length); + jpeg_rgb_decoder_addbits (dec, buffer->data, buffer->length); + swfdec_buffer_unref (buffer); jpeg_rgb_decoder_parse (dec); jpeg_rgb_decoder_get_image_size (dec, &image->width, &image->height); if (image->width == 0 || image->height == 0) { @@ -332,9 +310,9 @@ swfdec_image_jpeg3_load (SwfdecImage *im &image->rowstride, &image->width, &image->height); jpeg_rgb_decoder_free (dec); - bits.ptr += jpeg_length; - - alpha_data = lossless (bits.ptr, bits.end - bits.ptr, &len); + buffer = swfdec_bits_get_buffer (&bits, -1); + alpha_data = lossless (buffer->data, buffer->length, image->width * image->height); + swfdec_buffer_unref (buffer); merge_alpha (image, image_data, alpha_data); g_free (alpha_data); @@ -372,19 +350,12 @@ swfdec_image_lossless_load (SwfdecImage int format; int color_table_size; unsigned char *ptr; - int len; unsigned char *endptr; SwfdecBits bits; unsigned char *image_data = NULL; int have_alpha = (image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2); - bits.buffer = image->raw_data; - bits.ptr = image->raw_data->data; - bits.idx = 0; - bits.end = bits.ptr + image->raw_data->length; - endptr = bits.ptr + bits.buffer->length; - - bits.ptr += 2; + swfdec_bits_init (&bits, image->raw_data); format = swfdec_bits_get_u8 (&bits); SWFDEC_LOG (" format = %d", format); @@ -406,7 +377,7 @@ swfdec_image_lossless_load (SwfdecImage if (image->width == 0 || image->height == 0) return; swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height); - ptr = lossless (bits.ptr, endptr - bits.ptr, &len); + ptr = lossless (bits.ptr, endptr - bits.ptr, image->width * image->height); bits.ptr = endptr; if (format == 3) { @@ -531,9 +502,8 @@ tag_func_define_bits_lossless (SwfdecSwf return SWFDEC_STATUS_OK; image->type = SWFDEC_IMAGE_TYPE_LOSSLESS; - image->raw_data = swfdec_buffer_ref (bits->buffer); + image->raw_data = swfdec_bits_get_buffer (bits, -1); - bits->ptr += bits->buffer->length - 2; return SWFDEC_STATUS_OK; } @@ -552,9 +522,7 @@ tag_func_define_bits_lossless_2 (SwfdecS return SWFDEC_STATUS_OK; image->type = SWFDEC_IMAGE_TYPE_LOSSLESS2; - image->raw_data = swfdec_buffer_ref (bits->buffer); - - bits->ptr += bits->buffer->length - 2; + image->raw_data = swfdec_bits_get_buffer (bits, -1); return SWFDEC_STATUS_OK; } diff --git a/libswfdec/swfdec_swf_decoder.c b/libswfdec/swfdec_swf_decoder.c index e7be205..a43c9ac 100644 --- a/libswfdec/swfdec_swf_decoder.c +++ b/libswfdec/swfdec_swf_decoder.c @@ -239,7 +239,7 @@ swfdec_swf_decoder_parse (SwfdecDecoder { SwfdecSwfDecoder *s = SWFDEC_SWF_DECODER (dec); int ret = SWFDEC_STATUS_OK; - unsigned char *endptr; + const unsigned char *endptr; SwfdecBuffer *buffer; s->b = s->parse; diff --git a/libswfdec/swfdec_tag.c b/libswfdec/swfdec_tag.c index 4f57b1a..3896101 100644 --- a/libswfdec/swfdec_tag.c +++ b/libswfdec/swfdec_tag.c @@ -212,7 +212,6 @@ tag_func_define_sprite (SwfdecSwfDecoder s->parse_sprite = sprite; while (1) { - unsigned char *endptr; int x; int tag; guint tag_len; @@ -258,7 +257,7 @@ tag_func_define_sprite (SwfdecSwfDecoder SWFDEC_ERROR ("invalid tag %d %s during DefineSprite", tag, swfdec_swf_decoder_get_tag_name (tag)); } else { - endptr = parse.ptr + tag_len; + const unsigned char *endptr = parse.ptr + tag_len; ret = func (s); swfdec_bits_syncbits (bits); @@ -311,22 +310,11 @@ int tag_func_do_init_action (SwfdecSwfDecoder * s) { SwfdecBits *bits = &s->b; - int len; SwfdecBuffer *buffer; SwfdecCharacter *character; - unsigned char *endptr; - //int retcode = SWF_ERROR; - - endptr = bits->ptr + bits->buffer->length; character = swfdec_swf_decoder_get_character (s, swfdec_bits_get_u16 (bits)); - - len = bits->end - bits->ptr; - - buffer = swfdec_buffer_new_subbuffer (bits->buffer, - bits->ptr - bits->buffer->data, len); - - bits->ptr += len; + buffer = swfdec_bits_get_buffer (bits, -1); if (SWFDEC_IS_SPRITE (character)) { SWFDEC_WARNING ("init actions not implemented yet"); @@ -339,7 +327,6 @@ tag_func_do_init_action (SwfdecSwfDecode } swfdec_buffer_unref (buffer); - //return retcode; return SWFDEC_STATUS_OK; } @@ -389,11 +376,8 @@ tag_func_define_button_2 (SwfdecSwfDecod int flags; int offset; SwfdecButton *button; - unsigned char *endptr; char *script_name; - endptr = bits->ptr + bits->buffer->length; - id = swfdec_bits_get_u16 (bits); button = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_BUTTON); if (!button) @@ -476,11 +460,8 @@ tag_func_define_button (SwfdecSwfDecoder SwfdecBits *bits = &s->b; int id; SwfdecButton *button; - unsigned char *endptr; char *script_name; - endptr = bits->ptr + bits->buffer->length; - id = swfdec_bits_get_u16 (bits); button = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_BUTTON); if (!button) diff-tree c3f0eaf5706a0d972132a0ea4fcaff5aa79ec122 (from 3e6fcd37cb3157514beaf45cb90e2c68d2138b86) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 17 22:51:45 2007 +0100 add the SwfdecSCript to the stack frame also, some more functions are implemented (like WaitForFrame, it needs this) diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c index 1a45a77..1d15966 100644 --- a/libswfdec/js/jsinterp.c +++ b/libswfdec/js/jsinterp.c @@ -832,6 +832,7 @@ have_fun: frame.varobj = NULL; frame.callobj = frame.argsobj = NULL; frame.script = script; + frame.swf = swf; frame.fun = fun; frame.argc = argc; frame.argv = sp - argc; diff --git a/libswfdec/js/jsinterp.h b/libswfdec/js/jsinterp.h index d68957d..b22166d 100644 --- a/libswfdec/js/jsinterp.h +++ b/libswfdec/js/jsinterp.h @@ -54,7 +54,8 @@ struct JSStackFrame { JSObject *callobj; /* lazily created Call object */ JSObject *argsobj; /* lazily created arguments object */ JSObject *varobj; /* variables object, where vars go */ - JSScript *script; /* script being interpreted */ + JSScript *script; /* script being interpreted or NULL */ + void *swf; /* SwfdecScript being executed if script is NULL */ JSFunction *fun; /* function being called or null */ JSObject *thisp; /* "this" pointer if in method */ uintN argc; /* actual argument count */ diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 3d39a72..5b01510 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -29,7 +29,9 @@ /*** SUPPORT FUNCTIONS ***/ +#include "swfdec_decoder.h" #include "swfdec_movie.h" +#include "swfdec_root_movie.h" static SwfdecMovie * swfdec_action_get_target (JSContext *cx) @@ -45,9 +47,91 @@ swfdec_action_stop (JSContext *cx, guint SwfdecMovie *movie = swfdec_action_get_target (cx); if (movie) movie->stopped = TRUE; + else + SWFDEC_ERROR ("no movie to stop"); return JS_TRUE; } +static JSBool +swfdec_action_play (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + if (movie) + movie->stopped = FALSE; + else + SWFDEC_ERROR ("no movie to play"); + return JS_TRUE; +} + +static JSBool +swfdec_action_goto_frame (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + guint frame; + + if (len != 2) { + SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len); + return JS_FALSE; + } + frame = GUINT16_FROM_LE (*((guint16 *) data)); + if (movie) { + swfdec_movie_goto (movie, frame); + movie->stopped = TRUE; + } else { + SWFDEC_ERROR ("no movie to goto on"); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_wait_for_frame (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + guint frame, jump, loaded; + + if (len != 3) { + SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len); + return JS_TRUE; + } + if (movie == NULL) { + SWFDEC_ERROR ("no movie for WaitForFrame"); + return JS_TRUE; + } + + frame = GUINT16_FROM_LE (*((guint16 *) data)); + jump = data[2]; + if (SWFDEC_IS_ROOT_MOVIE (movie)) { + SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie->root)->decoder; + loaded = dec->frames_loaded; + g_assert (loaded <= movie->n_frames); + } else { + loaded = movie->n_frames; + } + if (loaded < frame) { + SwfdecScript *script = cx->fp->swf; + guint8 *pc = cx->fp->pc; + guint8 *endpc = script->buffer->data + script->buffer->length; + + /* jump instructions */ + g_assert (script); + do { + if (pc >= endpc) + break; + if (*pc & 0x80) { + if (pc + 2 >= endpc) + break; + pc += 3 + GUINT16_FROM_LE (*((guint16 *) (pc + 1))); + } else { + pc++; + } + } while (jump-- > 0); + cx->fp->pc = pc; + } + return JS_TRUE; +} + +/*** PRINT FUNCTIONS ***/ + static char * swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len) { @@ -93,7 +177,7 @@ static const SwfdecActionSpec actions[25 /* version 3 */ [0x04] = { "NextFrame", NULL }, [0x05] = { "PreviousFrame", NULL }, - [0x06] = { "Play", NULL }, + [0x06] = { "Play", NULL, 0, 0, { swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play } }, [0x07] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } }, [0x08] = { "ToggleQuality", NULL }, [0x09] = { "StopSounds", NULL }, @@ -182,13 +266,13 @@ static const SwfdecActionSpec actions[25 [0x69] = { "Extends", NULL }, /* version 3 */ - [0x81] = { "GotoFrame", swfdec_action_print_goto_frame }, + [0x81] = { "GotoFrame", swfdec_action_print_goto_frame, 0, 0, { swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame } }, [0x83] = { "GetURL", NULL }, /* version 5 */ [0x87] = { "StoreRegister", NULL }, [0x88] = { "ConstantPool", NULL }, /* version 3 */ - [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame }, + [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, [0x8b] = { "SetTarget", NULL }, [0x8c] = { "GotoLabel", NULL }, /* version 4 */ @@ -262,12 +346,14 @@ static gboolean validate_action (guint action, const guint8 *data, guint len, gpointer script) { /* we might want to do stuff here for certain actions */ +#if 0 { char *foo = swfdec_script_print_action (action, data, len); if (foo == NULL) return FALSE; g_print ("%s\n", foo); } +#endif return TRUE; } @@ -362,6 +448,7 @@ swfdec_script_interpret (SwfdecScript *s /* set up the script */ startpc = pc = script->buffer->data; endpc = startpc + script->buffer->length; + fp->pc = pc; /* set up stack */ startsp = js_AllocStack (cx, STACKSIZE, &mark); if (!startsp) { @@ -426,7 +513,11 @@ swfdec_script_interpret (SwfdecScript *s ok = spec->exec[version] (cx, action, data, len); if (!ok) goto out; - pc = nextpc; + if (fp->pc == pc) { + fp->pc = pc = nextpc; + } else { + pc = fp->pc; + } } out: @@ -482,6 +573,7 @@ swfdec_script_execute (SwfdecScript *scr frame.script = NULL; frame.varobj = obj; frame.fun = NULL; + frame.swf = script; frame.thisp = obj; frame.argc = frame.nvars = 0; frame.argv = frame.vars = NULL; diff-tree 3e6fcd37cb3157514beaf45cb90e2c68d2138b86 (from bbafcb875054f54987db4b37da1bd6f40ada79f4) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 17 22:51:10 2007 +0100 remove leftover code from when the root movie contained the root script diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c index 30eb161..f5bf871 100644 --- a/libswfdec/swfdec_js_movie.c +++ b/libswfdec/swfdec_js_movie.c @@ -693,8 +693,7 @@ mc_framesloaded (JSContext *cx, JSObject g_assert (movie); /* only root movies can be partially loaded */ - if (SWFDEC_IS_ROOT_MOVIE (movie) || - SWFDEC_IS_ROOT_MOVIE (movie->parent)) { + if (SWFDEC_IS_ROOT_MOVIE (movie)) { SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie->root)->decoder; loaded = dec->frames_loaded; g_assert (loaded <= movie->n_frames); diff-tree bbafcb875054f54987db4b37da1bd6f40ada79f4 (from 7005f0c65edf0177ea22cbb4514c7df1cbb099c1) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 17 16:06:25 2007 +0100 Add skeleton for interpreter I hope I know what I'm doing here diff --git a/libswfdec/Makefile.am b/libswfdec/Makefile.am index 485f97f..7233f02 100644 --- a/libswfdec/Makefile.am +++ b/libswfdec/Makefile.am @@ -15,6 +15,7 @@ lib_LTLIBRARIES = libswfdec-@SWFDEC_MAJO js_cflags = -I$(srcdir)/js/ -I./js -DXP_UNIX -DDEBUG +# swfdec_debugger.c libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES = \ swfdec_audio.c \ swfdec_audio_event.c \ @@ -32,9 +33,7 @@ libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES $(CODECS) \ swfdec_codec_screen.c \ swfdec_color.c \ - swfdec_compiler.c \ swfdec_debug.c \ - swfdec_debugger.c \ swfdec_decoder.c \ swfdec_edittext.c \ swfdec_edittext_movie.c \ @@ -64,6 +63,7 @@ libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES swfdec_rect.c \ swfdec_ringbuffer.c \ swfdec_root_movie.c \ + swfdec_script.c \ swfdec_scriptable.c \ swfdec_shape.c \ swfdec_sound.c \ @@ -109,7 +109,6 @@ noinst_HEADERS = \ swfdec_character.h \ swfdec_codec.h \ swfdec_color.h \ - swfdec_compiler.h \ swfdec_debug.h \ swfdec_debugger.h \ swfdec_decoder.h \ @@ -134,6 +133,7 @@ noinst_HEADERS = \ swfdec_rect.h \ swfdec_ringbuffer.h \ swfdec_root_movie.h \ + swfdec_script.h \ swfdec_scriptable.h \ swfdec_shape.h \ swfdec_sound.h \ diff --git a/libswfdec/js/jsfun.h b/libswfdec/js/jsfun.h index 5dad235..ad4249d 100644 --- a/libswfdec/js/jsfun.h +++ b/libswfdec/js/jsfun.h @@ -52,6 +52,7 @@ struct JSFunction { JSObject *object; /* back-pointer to GC'ed object header */ JSNative native; /* native method pointer or null */ JSScript *script; /* interpreted bytecode descriptor or null */ + void *swf; /* Actionscript or null */ uint16 nargs; /* minimum number of actual arguments */ uint16 extra; /* number of arg slots for local GC roots */ uint16 nvars; /* number of local variables */ diff --git a/libswfdec/js/jsgc.c b/libswfdec/js/jsgc.c index b25d2b5..88d64ca 100644 --- a/libswfdec/js/jsgc.c +++ b/libswfdec/js/jsgc.c @@ -1214,20 +1214,23 @@ restart: GC_MARK(cx, fp->argsobj, "arguments object", NULL); if (fp->varobj) GC_MARK(cx, fp->varobj, "variables object", NULL); - if (fp->script) { + if (fp->script) js_MarkScript(cx, fp->script, NULL); - if (fp->spbase) { - /* - * Don't mark what has not been pushed yet, or what - * has been popped already. - */ - depth = fp->script->depth; - nslots = (JS_UPTRDIFF(fp->sp, fp->spbase) - < depth * sizeof(jsval)) - ? (uintN)(fp->sp - fp->spbase) - : depth; - GC_MARK_JSVALS(cx, nslots, fp->spbase, "operand"); - } + if (fp->spbase) { + /* + * Don't mark what has not been pushed yet, or what + * has been popped already. + */ + if (fp->script) { + depth = fp->script->depth; + nslots = (JS_UPTRDIFF(fp->sp, fp->spbase) + < depth * sizeof(jsval)) + ? (uintN)(fp->sp - fp->spbase) + : depth; + } else { + nslots = JS_UPTRDIFF(fp->sp, fp->spbase); + } + GC_MARK_JSVALS(cx, nslots, fp->spbase, "operand"); } GC_MARK(cx, fp->thisp, "this", NULL); if (fp->argv) { diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c index ff45d22..1a45a77 100644 --- a/libswfdec/js/jsinterp.c +++ b/libswfdec/js/jsinterp.c @@ -626,6 +626,9 @@ ComputeThis(JSContext *cx, JSObject *thi return JS_TRUE; } +extern JSBool +swfdec_script_interpret(void *script, JSContext *cx, jsval *rval); + /* * Find a function reference and its 'this' object implicit first parameter * under argc arguments on cx's stack, and call the function. Push missing @@ -646,6 +649,7 @@ js_Invoke(JSContext *cx, uintN argc, uin JSNative native; JSFunction *fun; JSScript *script; + void *swf; uintN minargs, nvars; intN nslots, nalloc, surplus; JSInterpreterHook hook; @@ -815,6 +819,7 @@ have_fun: fun = (JSFunction *) JS_GetPrivate(cx, funobj); native = fun->native; script = fun->script; + swf = fun->swf; minargs = fun->nargs + fun->extra; nvars = fun->nvars; @@ -956,6 +961,9 @@ have_fun: #endif } ok = js_Interpret(cx, &v); + } else if (swf) { + frame.scopeChain = funobj; /* FIXME */ + ok = swfdec_script_interpret(swf, cx, &v); } else { /* fun might be onerror trying to report a syntax error in itself. */ frame.scopeChain = NULL; diff --git a/libswfdec/swfdec_button_movie.c b/libswfdec/swfdec_button_movie.c index 92d40b9..998413d 100644 --- a/libswfdec/swfdec_button_movie.c +++ b/libswfdec/swfdec_button_movie.c @@ -76,7 +76,8 @@ swfdec_button_movie_execute (SwfdecButto | SWFDEC_BUTTON_OVER_DOWN_TO_IDLE)) == 0); } if (movie->button->events) - swfdec_event_list_execute (movie->button->events, SWFDEC_MOVIE (movie)->parent, condition, 0); + swfdec_event_list_execute (movie->button->events, + SWFDEC_SCRIPTABLE (SWFDEC_MOVIE (movie)->parent), condition, 0); } #define CONTENT_IN_FRAME(content, frame) \ diff --git a/libswfdec/swfdec_compiler.c b/libswfdec/swfdec_compiler.c index abeec0b..45983b6 100644 --- a/libswfdec/swfdec_compiler.c +++ b/libswfdec/swfdec_compiler.c @@ -1246,23 +1246,6 @@ typedef struct { static const SwfdecActionSpec * swfdec_action_find (guint action); -void -swfdec_disassemble (SwfdecPlayer *player, JSScript *script) -{ - guint i; - - for (i = 0; i < script->length; i ++) { - g_print ("%02X ", script->code[i]); - if (i % 16 == 15) - g_print ("\n"); - else if (i % 4 == 3) - g_print (" "); - } - if (i % 16 != 15) - g_print ("\n"); - js_Disassemble (player->jscx, script, JS_TRUE, stdout); -} - /** * swfdec_compile: * @player: a #SwfdecPlayer diff --git a/libswfdec/swfdec_compiler.h b/libswfdec/swfdec_compiler.h index e91b7cd..d3b8c9c 100644 --- a/libswfdec/swfdec_compiler.h +++ b/libswfdec/swfdec_compiler.h @@ -6,10 +6,9 @@ #include <libswfdec/swfdec_bits.h> #include <libswfdec/swfdec_player.h> +#error "swfdec_compiler.h is out of the game now!" G_BEGIN_DECLS -void swfdec_disassemble (SwfdecPlayer * player, - JSScript * script); JSScript * swfdec_compile (SwfdecPlayer * player, SwfdecBits * bits, int version, diff --git a/libswfdec/swfdec_event.c b/libswfdec/swfdec_event.c index ca08fb7..7ed820b 100644 --- a/libswfdec/swfdec_event.c +++ b/libswfdec/swfdec_event.c @@ -22,17 +22,17 @@ #endif #include <js/jsapi.h> #include "swfdec_event.h" -#include "swfdec_compiler.h" #include "swfdec_debug.h" #include "swfdec_js.h" #include "swfdec_player_internal.h" +#include "swfdec_script.h" typedef struct _SwfdecEvent SwfdecEvent; struct _SwfdecEvent { unsigned int conditions; guint8 key; - JSScript * script; + SwfdecScript *script; }; struct _SwfdecEventList { @@ -81,7 +81,7 @@ swfdec_event_list_free (SwfdecEventList for (i = 0; i < list->events->len; i++) { SwfdecEvent *event = &g_array_index (list->events, SwfdecEvent, i); - swfdec_compiler_destroy_script (list->player, event->script); + swfdec_script_unref (event->script); } g_array_free (list->events, TRUE); g_free (list); @@ -146,14 +146,14 @@ swfdec_event_list_parse (SwfdecEventList event.key = key; name = g_strconcat (description, ".", swfdec_event_list_condition_name (conditions), NULL); - event.script = swfdec_compile (list->player, bits, version, name); + event.script = swfdec_script_new (bits, name, version); g_free (name); if (event.script) g_array_append_val (list->events, event); } void -swfdec_event_list_execute (SwfdecEventList *list, SwfdecMovie *movie, +swfdec_event_list_execute (SwfdecEventList *list, SwfdecScriptable *scriptable, unsigned int conditions, guint8 key) { unsigned int i; @@ -164,8 +164,8 @@ swfdec_event_list_execute (SwfdecEventLi SwfdecEvent *event = &g_array_index (list->events, SwfdecEvent, i); if ((event->conditions & conditions) && event->key == key) { - SWFDEC_LOG ("executing script for event %u on movie %s", conditions, movie->name); - swfdec_js_execute_script (list->player, movie, event->script, NULL); + SWFDEC_LOG ("executing script for event %u on scriptable %p", conditions, scriptable); + swfdec_script_execute (event->script, scriptable); } } } diff --git a/libswfdec/swfdec_event.h b/libswfdec/swfdec_event.h index 8251937..2906bb4 100644 --- a/libswfdec/swfdec_event.h +++ b/libswfdec/swfdec_event.h @@ -59,7 +59,7 @@ void swfdec_event_list_parse (SwfdecE guint8 key, const char * description); void swfdec_event_list_execute (SwfdecEventList * list, - SwfdecMovie * movie, + SwfdecScriptable * scriptable, unsigned int condition, guint8 key); gboolean swfdec_event_list_has_conditions(SwfdecEventList * list, diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 4ce01a5..cf14f65 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -30,7 +30,6 @@ #include "swfdec_player_internal.h" #include "swfdec_debug.h" #include "swfdec_js.h" -#include "swfdec_compiler.h" #include "swfdec_root_movie.h" #include "swfdec_swf_decoder.h" @@ -130,6 +129,23 @@ swfdec_js_finish_player (SwfdecPlayer *p } } +static void +swfdec_disassemble (SwfdecPlayer *player, JSScript *script) +{ + guint i; + + for (i = 0; i < script->length; i ++) { + g_print ("%02X ", script->code[i]); + if (i % 16 == 15) + g_print ("\n"); + else if (i % 4 == 3) + g_print (" "); + } + if (i % 16 != 15) + g_print ("\n"); + js_Disassemble (player->jscx, script, JS_TRUE, stdout); +} + /** * swfdec_js_execute_script: * @s: a @SwfdecPlayer diff --git a/libswfdec/swfdec_movie.c b/libswfdec/swfdec_movie.c index 16ff859..a851cd2 100644 --- a/libswfdec/swfdec_movie.c +++ b/libswfdec/swfdec_movie.c @@ -339,7 +339,7 @@ swfdec_movie_execute_script (SwfdecMovie guint condition = GPOINTER_TO_UINT (data); g_assert (movie->content->events); - swfdec_event_list_execute (movie->content->events, movie, condition, 0); + swfdec_event_list_execute (movie->content->events, SWFDEC_SCRIPTABLE (movie), condition, 0); } /** diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c new file mode 100644 index 0000000..3d39a72 --- /dev/null +++ b/libswfdec/swfdec_script.c @@ -0,0 +1,523 @@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "swfdec_script.h" +#include "swfdec_debug.h" +#include "swfdec_scriptable.h" +#include "js/jscntxt.h" +#include "js/jsinterp.h" + +/*** SUPPORT FUNCTIONS ***/ + +#include "swfdec_movie.h" + +static SwfdecMovie * +swfdec_action_get_target (JSContext *cx) +{ + return swfdec_scriptable_from_jsval (cx, OBJECT_TO_JSVAL (cx->fp->scopeChain), SWFDEC_TYPE_MOVIE); +} + +/*** ALL THE ACTION IS HERE ***/ + +static JSBool +swfdec_action_stop (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + if (movie) + movie->stopped = TRUE; + return JS_TRUE; +} + +static char * +swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len) +{ + guint frame; + + if (len != 2) + return NULL; + + frame = GUINT16_FROM_LE (*((guint16 *) data)); + return g_strdup_printf ("GotoFrame %u", frame); +} + +static char * +swfdec_action_print_wait_for_frame (guint action, const guint8 *data, guint len) +{ + guint frame, jump; + + if (len != 3) + return NULL; + + frame = GUINT16_FROM_LE (*((guint16 *) data)); + jump = data[2]; + return g_strdup_printf ("WaitForFrame %u %u", frame, jump); +} + +/*** BIG FUNCTION TABLE ***/ + +/* defines minimum and maximum versions for which we have seperate scripts */ +#define MINSCRIPTVERSION 3 +#define MAXSCRIPTVERSION 7 + +typedef JSBool (* SwfdecActionExec) (JSContext *cx, guint action, const guint8 *data, guint len); +typedef struct { + const char * name; /* name identifying the action */ + char * (* print) (guint action, const guint8 *data, guint len); + int remove; /* values removed from stack or -1 for dynamic */ + guint add; /* values added to the stack */ + SwfdecActionExec exec[MAXSCRIPTVERSION - MINSCRIPTVERSION + 1]; + /* array is for version 3, 4, 5, 6, 7+ */ +} SwfdecActionSpec; + +static const SwfdecActionSpec actions[256] = { + /* version 3 */ + [0x04] = { "NextFrame", NULL }, + [0x05] = { "PreviousFrame", NULL }, + [0x06] = { "Play", NULL }, + [0x07] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } }, + [0x08] = { "ToggleQuality", NULL }, + [0x09] = { "StopSounds", NULL }, + /* version 4 */ + [0x0a] = { "Add", NULL }, + [0x0b] = { "Subtract", NULL }, + [0x0c] = { "Multiply", NULL }, + [0x0d] = { "Divide", NULL }, + [0x0e] = { "Equals", NULL }, + [0x0f] = { "Less", NULL }, + [0x10] = { "And", NULL }, + [0x11] = { "Or", NULL }, + [0x12] = { "Not", NULL }, + [0x13] = { "StringEquals", NULL }, + [0x14] = { "StringLength", NULL }, + [0x15] = { "StringExtract", NULL }, + [0x17] = { "Pop", NULL }, + [0x18] = { "ToInteger", NULL }, + [0x1c] = { "GetVariable", NULL }, + [0x1d] = { "SetVariable", NULL }, + [0x20] = { "SetTarget2", NULL }, + [0x21] = { "StringAdd", NULL }, + [0x22] = { "GetProperty", NULL }, + [0x23] = { "SetProperty", NULL }, + [0x24] = { "CloneSprite", NULL }, + [0x25] = { "RemoveSprite", NULL }, + [0x26] = { "Trace", NULL }, + [0x27] = { "StartDrag", NULL }, + [0x28] = { "EndDrag", NULL }, + [0x29] = { "StringLess", NULL }, + /* version 7 */ + [0x2a] = { "Throw", NULL }, + [0x2b] = { "Cast", NULL }, + [0x2c] = { "Implements", NULL }, + /* version 4 */ + [0x30] = { "RandomNumber", NULL }, + [0x31] = { "MBStringLength", NULL }, + [0x32] = { "CharToAscii", NULL }, + [0x33] = { "AsciiToChar", NULL }, + [0x34] = { "GetTime", NULL }, + [0x35] = { "MBStringExtract", NULL }, + [0x36] = { "MBCharToAscii", NULL }, + [0x37] = { "MVAsciiToChar", NULL }, + /* version 5 */ + [0x3a] = { "Delete", NULL }, + [0x3b] = { "Delete2", NULL }, + [0x3c] = { "DefineLocal", NULL }, + [0x3d] = { "CallFunction", NULL }, + [0x3e] = { "Return", NULL }, + [0x3f] = { "Modulo", NULL }, + [0x40] = { "NewObject", NULL }, + [0x41] = { "DefineLocal2", NULL }, + [0x42] = { "InitArray", NULL }, + [0x43] = { "InitObject", NULL }, + [0x44] = { "Typeof", NULL }, + [0x45] = { "TargetPath", NULL }, + [0x46] = { "Enumerate", NULL }, + [0x47] = { "Add2", NULL }, + [0x48] = { "Less2", NULL }, + [0x49] = { "Equals2", NULL }, + [0x4a] = { "ToNumber", NULL }, + [0x4b] = { "ToString", NULL }, + [0x4c] = { "PushDuplicate", NULL }, + [0x4d] = { "Swap", NULL }, + [0x4e] = { "GetMember", NULL }, + [0x4f] = { "SetMember", NULL }, /* apparently the result is ignored */ + [0x50] = { "Increment", NULL }, + [0x51] = { "Decrement", NULL }, + [0x52] = { "CallMethod", NULL }, + [0x53] = { "NewMethod", NULL }, + /* version 6 */ + [0x54] = { "InstanceOf", NULL }, + [0x55] = { "Enumerate2", NULL }, + /* version 5 */ + [0x60] = { "BitAnd", NULL }, + [0x61] = { "BitOr", NULL }, + [0x62] = { "BitXor", NULL }, + [0x63] = { "BitLShift", NULL }, + [0x64] = { "BitRShift", NULL }, + [0x65] = { "BitURShift", NULL }, + /* version 6 */ + [0x66] = { "StrictEquals", NULL }, + [0x67] = { "Greater", NULL }, + [0x68] = { "StringGreater", NULL }, + /* version 7 */ + [0x69] = { "Extends", NULL }, + + /* version 3 */ + [0x81] = { "GotoFrame", swfdec_action_print_goto_frame }, + [0x83] = { "GetURL", NULL }, + /* version 5 */ + [0x87] = { "StoreRegister", NULL }, + [0x88] = { "ConstantPool", NULL }, + /* version 3 */ + [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame }, + [0x8b] = { "SetTarget", NULL }, + [0x8c] = { "GotoLabel", NULL }, + /* version 4 */ + [0x8d] = { "WaitForFrame2", NULL }, + /* version 7 */ + [0x8e] = { "DefineFunction2", NULL }, + [0x8f] = { "Try", NULL }, + /* version 5 */ + [0x94] = { "With", NULL }, + /* version 4 */ + [0x96] = { "Push", NULL }, + [0x99] = { "Jump", NULL }, + [0x9a] = { "GetURL2", NULL }, + /* version 5 */ + [0x9b] = { "DefineFunction", NULL }, + /* version 4 */ + [0x9d] = { "If", NULL }, + [0x9e] = { "Call", NULL }, + [0x9f] = { "GotoFrame2", NULL } +}; + +char * +swfdec_script_print_action (guint action, const guint8 *data, guint len) +{ + const SwfdecActionSpec *spec = actions + action; + + if (action & 0x80) { + if (spec->print == NULL) { + SWFDEC_ERROR ("action %u %s has no print statement", + action, spec->name ? spec->name : "Unknown"); + return NULL; + } + return spec->print (action, data, len); + } else { + if (spec->name == NULL) { + SWFDEC_ERROR ("action %u is unknown", action); + return NULL; + } + return g_strdup (spec->name); + } +} + +typedef gboolean (* SwfdecScriptForeachFunc) (guint action, const guint8 *data, guint len, gpointer user_data); +static gboolean +swfdec_script_foreach (SwfdecBits *bits, SwfdecScriptForeachFunc func, gpointer user_data) +{ + guint action, len; + guint8 *data; + + while ((action = swfdec_bits_get_u8 (bits))) { + if (action & 0x80) { + len = swfdec_bits_get_u16 (bits); + data = bits->ptr; + } else { + len = 0; + data = NULL; + } + if (swfdec_bits_skip_bytes (bits, len) != len) { + SWFDEC_ERROR ("script too short"); + return FALSE; + } + if (!func (action, data, len, user_data)) + return FALSE; + } + return TRUE; +} + +/*** PUBLIC API ***/ + +static gboolean +validate_action (guint action, const guint8 *data, guint len, gpointer script) +{ + /* we might want to do stuff here for certain actions */ + { + char *foo = swfdec_script_print_action (action, data, len); + if (foo == NULL) + return FALSE; + g_print ("%s\n", foo); + } + return TRUE; +} + +SwfdecScript * +swfdec_script_new (SwfdecBits *bits, const char *name, unsigned int version) +{ + SwfdecScript *script; + guchar *start; + + g_return_val_if_fail (bits != NULL, NULL); + if (version < MINSCRIPTVERSION) { + SWFDEC_ERROR ("swfdec version %u doesn't support scripts", version); + return NULL; + } + + swfdec_bits_syncbits (bits); + start = bits->ptr; + script = g_new0 (SwfdecScript, 1); + script->refcount = 1; + script->name = g_strdup (name ? name : "Unnamed script"); + script->version = version; + + if (!swfdec_script_foreach (bits, validate_action, script)) { + /* assign a random buffer here so we have something to unref */ + script->buffer = bits->buffer; + swfdec_buffer_ref (script->buffer); + swfdec_script_unref (script); + return NULL; + } + script->buffer = swfdec_buffer_new_subbuffer (bits->buffer, start - bits->buffer->data, + bits->ptr - start); + return script; +} + +void +swfdec_script_ref (SwfdecScript *script) +{ + g_return_if_fail (script != NULL); + + script->refcount++; +} + +void +swfdec_script_unref (SwfdecScript *script) +{ + g_return_if_fail (script != NULL); + g_return_if_fail (script->refcount > 0); + + script->refcount--; + if (script->refcount > 0) + return; + + swfdec_buffer_unref (script->buffer); + g_free (script->name); + g_free (script); +} + +#ifndef MAX_INTERP_LEVEL +#if defined(XP_OS2) +#define MAX_INTERP_LEVEL 250 +#elif defined _MSC_VER && _MSC_VER <= 800 +#define MAX_INTERP_LEVEL 30 +#else +#define MAX_INTERP_LEVEL 1000 +#endif +#endif + +/* random guess */ +#define STACKSIZE 100 + +/* FIXME: the implementation of this function needs the usual debugging hooks + * found in mozilla */ +JSBool +swfdec_script_interpret (SwfdecScript *script, JSContext *cx, jsval *rval) +{ + JSStackFrame *fp; + guint8 *startpc, *pc, *endpc, *nextpc; + JSBool ok = JS_TRUE; + void *mark; + jsval *startsp, *endsp; + int stack_check; + guint action, len; + guint8 *data; + guint version; + const SwfdecActionSpec *spec; + + /* set up general stuff */ + swfdec_script_ref (script); + version = MAX (script->version - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION); + *rval = JSVAL_VOID; + fp = cx->fp; + /* set up the script */ + startpc = pc = script->buffer->data; + endpc = startpc + script->buffer->length; + /* set up stack */ + startsp = js_AllocStack (cx, STACKSIZE, &mark); + if (!startsp) { + ok = JS_FALSE; + goto out; + } + fp->spbase = startsp; + fp->sp = startsp; + endsp = startsp + STACKSIZE; + /* Check for too much nesting, or too deep a C stack. */ + if (++cx->interpLevel == MAX_INTERP_LEVEL || + !JS_CHECK_STACK_SIZE(cx, stack_check)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); + ok = JS_FALSE; + goto out; + } + + /* only valid return value */ + while (TRUE) { + /* check pc */ + if (pc < startpc || pc >= endpc) { + SWFDEC_ERROR ("pc %p not in valid range [%p, %p] anymore", pc, startpc, endpc); + goto internal_error; + } + /* decode next action */ + action = *pc; + spec = actions + action; + if (action == 0) + break; + if (action & 0x80) { + if (pc + 2 >= endpc) { + SWFDEC_ERROR ("action %u length value out of range", action); + goto internal_error; + } + data = pc + 3; + len = pc[1] | pc[2] << 8; + if (data + len > endpc) { + SWFDEC_ERROR ("action %u length %u out of range", action, len); + goto internal_error; + } + nextpc = pc + 3 + len; + } else { + data = NULL; + len = 0; + nextpc = pc + 1; + } + /* check action is valid */ + if (spec->exec[version] == NULL) { + SWFDEC_ERROR ("cannot interpret action %u %s for version %u", action, + spec->name ? spec->name : "Unknown", script->version); + goto internal_error; + } + if (fp->sp - spec->remove < startsp) { + SWFDEC_ERROR ("stack underflow while trying to execute %s - requires %u args, only got %u", + spec->name, spec->remove, fp->sp - fp->spbase); + goto internal_error; + } + if (fp->sp + spec->add - MAX (spec->remove, 0) > endsp) { + SWFDEC_ERROR ("FIXME: implement stack expansion, we got an overflow"); + goto internal_error; + } + ok = spec->exec[version] (cx, action, data, len); + if (!ok) + goto out; + pc = nextpc; + } + +out: +#if 0 + /* FIXME: exception handling */ + if (!ok && cx->throwing) { + /* + * Look for a try block within this frame that can catch the exception. + */ + SCRIPT_FIND_CATCH_START(script, pc, pc); + if (pc) { + len = 0; + cx->throwing = JS_FALSE; /* caught */ + ok = JS_TRUE; + goto advance_pc; + } + } +#endif +no_catch: + + /* Reset sp before freeing stack slots, because our caller may GC soon. */ + fp->sp = fp->spbase; + fp->spbase = NULL; + js_FreeStack(cx, mark); + cx->interpLevel--; + swfdec_script_unref (script); + return ok; + +internal_error: + *rval = JSVAL_VOID; + ok = JS_TRUE; + goto no_catch; +} + +jsval +swfdec_script_execute (SwfdecScript *script, SwfdecScriptable *scriptable) +{ + JSContext *cx; + JSStackFrame *oldfp, frame; + JSObject *obj; + JSBool ok; + + g_return_val_if_fail (script != NULL, JSVAL_VOID); + g_return_val_if_fail (SWFDEC_IS_SCRIPTABLE (scriptable), JSVAL_VOID); + + cx = scriptable->jscx; + obj = swfdec_scriptable_get_object (scriptable); + if (obj == NULL) + return JSVAL_VOID; + oldfp = cx->fp; + + frame.callobj = frame.argsobj = NULL; + frame.script = NULL; + frame.varobj = obj; + frame.fun = NULL; + frame.thisp = obj; + frame.argc = frame.nvars = 0; + frame.argv = frame.vars = NULL; + frame.annotation = NULL; + frame.sharpArray = NULL; + frame.rval = JSVAL_VOID; + frame.down = NULL; + frame.scopeChain = obj; + frame.pc = NULL; + frame.sp = oldfp ? oldfp->sp : NULL; + frame.spbase = NULL; + frame.sharpDepth = 0; + frame.flags = 0; + frame.dormantNext = NULL; + frame.objAtomMap = NULL; + + if (oldfp) { + g_assert (!oldfp->dormantNext); + oldfp->dormantNext = cx->dormantFrameChain; + cx->dormantFrameChain = oldfp; + } + + cx->fp = &frame; + + /* + * Use frame.rval, not result, so the last result stays rooted across any + * GC activations nested within this js_Interpret. + */ + ok = swfdec_script_interpret (script, cx, &frame.rval); + + cx->fp = oldfp; + if (oldfp) { + g_assert (cx->dormantFrameChain == oldfp); + cx->dormantFrameChain = oldfp->dormantNext; + oldfp->dormantNext = NULL; + } + + return ok ? frame.rval : JSVAL_VOID; +} diff --git a/libswfdec/swfdec_script.h b/libswfdec/swfdec_script.h new file mode 100644 index 0000000..d8688c3 --- /dev/null +++ b/libswfdec/swfdec_script.h @@ -0,0 +1,57 @@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef _SWFDEC_SCRIPT_H_ +#define _SWFDEC_SCRIPT_H_ + +#include <libswfdec/swfdec.h> +#include <libswfdec/swfdec_types.h> +#include <libswfdec/swfdec_bits.h> +#include <libswfdec/js/jsapi.h> + +G_BEGIN_DECLS + +//typedef struct _SwfdecScript SwfdecScript; + +/* FIXME: May want to typedef to SwfdecBuffer directly */ +struct _SwfdecScript { + SwfdecBuffer * buffer; /* buffer holding the script */ + unsigned int refcount; /* reference count */ + char * name; /* name identifying this script */ + unsigned int version; /* version of the script */ +}; + +SwfdecScript * swfdec_script_new (SwfdecBits * bits, + const char * name, + unsigned int version); +void swfdec_script_ref (SwfdecScript * script); +void swfdec_script_unref (SwfdecScript * script); + +JSBool swfdec_script_interpret (SwfdecScript * script, + JSContext * cx, + jsval * rval); +jsval swfdec_script_execute (SwfdecScript * script, + SwfdecScriptable * scriptable); + +char * swfdec_script_print_action (guint action, + const guint8 * data, + guint len); +G_END_DECLS + +#endif diff --git a/libswfdec/swfdec_sprite.c b/libswfdec/swfdec_sprite.c index ffb8eb7..7f1668e 100644 --- a/libswfdec/swfdec_sprite.c +++ b/libswfdec/swfdec_sprite.c @@ -25,10 +25,10 @@ #include <string.h> #include "swfdec_sprite.h" -#include "swfdec_compiler.h" #include "swfdec_debug.h" #include "swfdec_movie.h" #include "swfdec_player_internal.h" +#include "swfdec_script.h" #include "swfdec_sound.h" #include "swfdec_sprite_movie.h" #include "swfdec_swf_decoder.h" @@ -65,7 +65,7 @@ swfdec_sprite_dispose (GObject *object) &g_array_index (sprite->frames[i].actions, SwfdecSpriteAction, j); switch (action->type) { case SWFDEC_SPRITE_ACTION_SCRIPT: - swfdec_compiler_destroy_script (sprite->player, action->data); + swfdec_script_unref (action->data); break; case SWFDEC_SPRITE_ACTION_ADD: case SWFDEC_SPRITE_ACTION_UPDATE: diff --git a/libswfdec/swfdec_sprite_movie.c b/libswfdec/swfdec_sprite_movie.c index f303f33..8485d82 100644 --- a/libswfdec/swfdec_sprite_movie.c +++ b/libswfdec/swfdec_sprite_movie.c @@ -29,6 +29,7 @@ #include "swfdec_player_internal.h" #include "swfdec_ringbuffer.h" #include "swfdec_root_movie.h" +#include "swfdec_script.h" #include "swfdec_sprite.h" static SwfdecMovie * @@ -63,8 +64,7 @@ swfdec_sprite_movie_remove_child (Swfdec static void swfdec_sprite_movie_run_script (SwfdecMovie *movie, gpointer data) { - SwfdecPlayer *player = SWFDEC_ROOT_MOVIE (movie->root)->player; - swfdec_js_execute_script (player, movie, data, NULL); + swfdec_script_execute (data, SWFDEC_SCRIPTABLE (movie)); } static void diff --git a/libswfdec/swfdec_tag.c b/libswfdec/swfdec_tag.c index 7b6f00e..4f57b1a 100644 --- a/libswfdec/swfdec_tag.c +++ b/libswfdec/swfdec_tag.c @@ -31,7 +31,6 @@ #include "swfdec_tag.h" #include "swfdec_bits.h" #include "swfdec_button.h" -#include "swfdec_compiler.h" #include "swfdec_debug.h" #include "swfdec_edittext.h" #include "swfdec_font.h" @@ -39,6 +38,7 @@ #include "swfdec_morphshape.h" #include "swfdec_movie.h" /* for SwfdecContent */ #include "swfdec_pattern.h" +#include "swfdec_script.h" #include "swfdec_shape.h" #include "swfdec_sound.h" #include "swfdec_sprite.h" @@ -293,12 +293,12 @@ tag_func_define_sprite (SwfdecSwfDecoder int tag_func_do_action (SwfdecSwfDecoder * s) { - JSScript *script; + SwfdecScript *script; char *name; name = g_strdup_printf ("Sprite%u.Frame%u", SWFDEC_CHARACTER (s->parse_sprite)->id, s->parse_sprite->parse_frame); - script = swfdec_compile (SWFDEC_DECODER (s)->player, &s->b, s->version, name); + script = swfdec_script_new (&s->b, name, s->version); g_free (name); if (script) swfdec_sprite_add_action (s->parse_sprite, s->parse_sprite->parse_frame, diff --git a/libswfdec/swfdec_types.h b/libswfdec/swfdec_types.h index 49212d5..3228a36 100644 --- a/libswfdec/swfdec_types.h +++ b/libswfdec/swfdec_types.h @@ -44,6 +44,7 @@ typedef struct _SwfdecShape SwfdecShape; typedef struct _SwfdecShapeVec SwfdecShapeVec; typedef struct _SwfdecRect SwfdecRect; typedef struct _SwfdecRootMovie SwfdecRootMovie; +typedef struct _SwfdecScript SwfdecScript; typedef struct _SwfdecScriptable SwfdecScriptable; typedef struct _SwfdecSound SwfdecSound; typedef struct _SwfdecSoundChunk SwfdecSoundChunk;
Reasonably Related Threads
- Branch 'interpreter' - 28 commits - configure.ac libswfdec/js libswfdec/swfdec_buffer.c libswfdec/swfdec_edittext_movie.c libswfdec/swfdec_js.c libswfdec/swfdec_js_global.c libswfdec/swfdec_js.h libswfdec/swfdec_js_movie.c libswfdec/swfdec_player.c
- Branch 'interpreter' - 8 commits - libswfdec/swfdec_bits.c libswfdec/swfdec_bits.h libswfdec/swfdec_js.c libswfdec/swfdec_js.h libswfdec/swfdec_script.c test/swfdec_out.c test/swfdec_out.h test/swfedit_tag.c test/swfedit_token.c test/swfedit_token.h
- Branch 'interpreter' - 9 commits - libswfdec/js libswfdec/Makefile.am libswfdec/swfdec_debugger.c libswfdec/swfdec_debugger.h libswfdec/swfdec_edittext_movie.c libswfdec/swfdec_event.c libswfdec/swfdec_js.c libswfdec/swfdec_js_global.c
- Branch 'interpreter' - 18 commits - libswfdec/swfdec_image.c libswfdec/swfdec_image.h libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c libswfdec/swfdec_js_sound.c libswfdec/swfdec_pattern.c libswfdec/swfdec_scriptable.c libswfdec/swfdec_script.c
- 17 commits - libswfdec/js libswfdec/swfdec_js.c libswfdec/swfdec_js_global.c libswfdec/swfdec_js.h libswfdec/swfdec_js_movie.c libswfdec/swfdec_movie.c libswfdec/swfdec_player.c libswfdec/swfdec_player_internal.h libswfdec/swfdec_root_movie.c