[Swfdec] Branch 'interpreter' - 28 commits - configure.ac libswfdec/js libswfdec/swfdec_buffer.c libswfdec/swfdec_edittext_movie.c libswfdec/swfdec_js.c libswfdec/swfdec_js_global.c libswfdec/swfdec_js.h libswfdec/swfdec_js_movie.c libswfdec/swfdec_player.c libswfdec/swfdec_player_internal.h libswfdec/swfdec_script.c libswfdec/swfdec_swf_decoder.c test/.gitignore test/Makefile.am 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

Benjamin Otte company at kemper.freedesktop.org
Wed Jan 24 06:13:59 PST 2007


 configure.ac                       |    2 
 libswfdec/js/jsatom.c              |    6 
 libswfdec/js/jsatom.h              |    1 
 libswfdec/swfdec_buffer.c          |    7 
 libswfdec/swfdec_edittext_movie.c  |    4 
 libswfdec/swfdec_js.c              |   39 +-
 libswfdec/swfdec_js.h              |    3 
 libswfdec/swfdec_js_global.c       |    5 
 libswfdec/swfdec_js_movie.c        |    1 
 libswfdec/swfdec_player.c          |   10 
 libswfdec/swfdec_player_internal.h |    2 
 libswfdec/swfdec_script.c          |  538 +++++++++++++++++++++++++++++++++++--
 libswfdec/swfdec_swf_decoder.c     |    2 
 test/.gitignore                    |    1 
 test/Makefile.am                   |    2 
 test/swfdec_out.c                  |  236 ++++++++++++++++
 test/swfdec_out.h                  |   73 +++++
 test/swfedit.c                     |   58 +++
 test/swfedit_file.c                |  114 ++++++-
 test/swfedit_file.h                |    6 
 test/swfedit_tag.c                 |  132 +++++++++
 test/swfedit_tag.h                 |   16 -
 test/swfedit_token.c               |  151 ++++++----
 test/swfedit_token.h               |   11 
 24 files changed, 1275 insertions(+), 145 deletions(-)

New commits:
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 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 },


More information about the Swfdec mailing list