[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

Benjamin Otte company at kemper.freedesktop.org
Tue Feb 6 05:59:20 PST 2007


 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 at 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 at 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 at 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 at 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 at 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 at 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 at schleef.org>
   *		 2005-2006 Eric Anholt <eric at anholt.net>
-- *		      2006 Benjamin Otte <otte at gnome.org>
++ *		 2006-2007 Benjamin Otte <otte at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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- at SWFDEC_MAJO
 
 js_cflags = -I$(srcdir)/js/ -I./js -DXP_UNIX -DDEBUG
 
-# swfdec_debugger.c 
 libswfdec_ at SWFDEC_MAJORMINOR@_la_SOURCES = \
 	swfdec_audio.c \
 	swfdec_audio_event.c \
@@ -34,6 +33,7 @@ libswfdec_ at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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- at SWFDEC_MAJO
 
 js_cflags = -I$(srcdir)/js/ -I./js -DXP_UNIX -DDEBUG
 
+# swfdec_debugger.c 
 libswfdec_ at SWFDEC_MAJORMINOR@_la_SOURCES = \
 	swfdec_audio.c \
 	swfdec_audio_event.c \
@@ -32,9 +33,7 @@ libswfdec_ at 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_ at 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 at 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 at 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;


More information about the Swfdec mailing list