[Swfdec] 12 commits - configure.ac doc/swfdec.types Makefile.am test/crashfinder.c test/dump.c test/Makefile.am test/swfdec-extract.c test/swfdec_out.c test/swfdec_out.h test/swfedit.c test/swfedit_file.c test/swfedit_file.h test/swfedit_list.c test/swfedit_list.h test/swfedit_tag.c test/swfedit_tag.h test/swfedit_token.c test/swfedit_token.h test/swfscript.c test/test tools/crashfinder.c tools/dump.c tools/.gitignore tools/Makefile.am tools/swfdec-extract.c tools/swfdec_out.c tools/swfdec_out.h tools/swfedit.c tools/swfedit_file.c tools/swfedit_file.h tools/swfedit_list.c tools/swfedit_list.h tools/swfedit_tag.c tools/swfedit_tag.h tools/swfedit_token.c tools/swfedit_token.h tools/swfscript.c vivified/core

Benjamin Otte company at kemper.freedesktop.org
Mon Jan 7 10:39:16 PST 2008


 Makefile.am                         |    3 
 configure.ac                        |    2 
 doc/swfdec.types                    |    8 
 test/Makefile.am                    |   45 --
 test/crashfinder.c                  |  157 -------
 test/dump.c                         |  448 --------------------
 test/swfdec-extract.c               |  301 -------------
 test/swfdec_out.c                   |  383 -----------------
 test/swfdec_out.h                   |   88 ---
 test/swfedit.c                      |  138 ------
 test/swfedit_file.c                 |  297 -------------
 test/swfedit_file.h                 |   60 --
 test/swfedit_list.c                 |  149 ------
 test/swfedit_list.h                 |   61 --
 test/swfedit_tag.c                  |  507 ----------------------
 test/swfedit_tag.h                  |   83 ---
 test/swfedit_token.c                |  797 ------------------------------------
 test/swfedit_token.h                |  109 ----
 test/swfscript.c                    |  298 -------------
 test/test/.gitignore                |    4 
 test/test/Makefile.am               |   31 +
 test/test/compiler.c                |   57 ++
 test/test/swfdec_test.c             |  141 ++++++
 test/test/swfdec_test_function.c    |   67 +++
 test/test/swfdec_test_function.h    |   35 +
 test/test/swfdec_test_global.c      |   40 +
 test/test/swfdec_test_initialize.as |   34 +
 test/test/swfdec_test_initialize.h  |   32 +
 test/test/swfdec_test_test.c        |  262 +++++++++++
 test/test/swfdec_test_test.h        |   62 ++
 tools/.gitignore                    |   17 
 tools/Makefile.am                   |   41 +
 tools/crashfinder.c                 |  157 +++++++
 tools/dump.c                        |  448 ++++++++++++++++++++
 tools/swfdec-extract.c              |  301 +++++++++++++
 tools/swfdec_out.c                  |  383 +++++++++++++++++
 tools/swfdec_out.h                  |   88 +++
 tools/swfedit.c                     |  138 ++++++
 tools/swfedit_file.c                |  297 +++++++++++++
 tools/swfedit_file.h                |   60 ++
 tools/swfedit_list.c                |  149 ++++++
 tools/swfedit_list.h                |   61 ++
 tools/swfedit_tag.c                 |  507 ++++++++++++++++++++++
 tools/swfedit_tag.h                 |   83 +++
 tools/swfedit_token.c               |  797 ++++++++++++++++++++++++++++++++++++
 tools/swfedit_token.h               |  109 ++++
 tools/swfscript.c                   |  298 +++++++++++++
 vivified/core/Makefile.am           |    2 
 48 files changed, 4712 insertions(+), 3923 deletions(-)

New commits:
commit abfc9954a36911aabc29ca2252628e7925287757
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 19:38:36 2008 +0100

    move tools from test/ to tools/

diff --git a/Makefile.am b/Makefile.am
index 0c33e5c..d13fae6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,7 +18,8 @@ SUBDIRS= \
 	$(GTK_SUBDIRS) \
 	$(VIVI_SUBDIRS) \
 	data \
-	test
+	test \
+	tools
 
 ACLOCAL_FLAGS = -I m4
 
diff --git a/configure.ac b/configure.ac
index 98d756a..338ca51 100644
--- a/configure.ac
+++ b/configure.ac
@@ -357,6 +357,7 @@ test/sound/Makefile
 test/test/Makefile
 test/trace/Makefile
 test/various/Makefile
+tools/Makefile
 vivified/Makefile
 vivified/core/Makefile
 vivified/dock/Makefile
diff --git a/test/Makefile.am b/test/Makefile.am
index d69a082..c8cbfbc 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,44 +1 @@
 SUBDIRS = image sound test trace various
-
-
-if WITH_GTK
-noinst_LTLIBRARIES = libswfedit.la
-noinst_PROGRAMS = swfdec-extract dump swfedit swfscript crashfinder
-else
-noinst_PROGRAMS = swfdec-extract dump crashfinder
-endif
-
-crashfinder_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
-crashfinder_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS)
-crashfinder_SOURCES = crashfinder.c
-
-dump_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS)
-dump_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
-
-swfdec_extract_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS)
-swfdec_extract_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS)
-
-libswfedit_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(GTK_CFLAGS)
-libswfedit_la_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS)
-
-swfedit_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(GTK_CFLAGS)
-swfedit_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS)
-swfedit_LDADD = libswfedit.la
-
-swfscript_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(GTK_CFLAGS)
-swfscript_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS)
-swfscript_LDADD = libswfedit.la
-
-libswfedit_la_SOURCES = \
-	swfdec_out.c \
-	swfedit_file.c \
-	swfedit_list.c \
-	swfedit_tag.c \
-	swfedit_token.c
-
-noinst_HEADERS = \
-	swfdec_out.h \
-	swfedit_file.h \
-	swfedit_list.h \
-	swfedit_tag.h \
-	swfedit_token.h
diff --git a/test/crashfinder.c b/test/crashfinder.c
deleted file mode 100644
index 3c4a4a7..0000000
--- a/test/crashfinder.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Swfdec
- * Copyright (C) 2007 Pekka Lampila <pekka.lampila at iki.fi>
- *               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 <libswfdec/swfdec.h>
-
-int
-main (int argc, char **argv)
-{
-  GOptionContext *context;
-  GError *err;
-  SwfdecPlayer *player;
-  SwfdecLoader *loader;
-  guint i;
-  cairo_surface_t *surface;
-  cairo_t *cr;
-  gboolean aborts;
-  glong play_per_file = 30;
-  glong max_per_file = 60;
-  glong max_per_advance = 10;
-  GTimer *timer;
-  char **filenames = NULL;
-  const GOptionEntry entries[] = {
-    {
-      "play-time", 'p', 0, G_OPTION_ARG_INT, &play_per_file,
-      "How many seconds will be played from each file (default 30)", NULL
-    },
-    {
-      "max-per-file", '\0', 0, G_OPTION_ARG_INT, &max_per_file,
-      "Maximum runtime in seconds allowed for each file (default 60)", NULL
-    },
-    {
-      "max-per-advance", '\0', 0, G_OPTION_ARG_INT, &max_per_advance,
-      "Maximum runtime in seconds allowed for each advance (default 10)", NULL
-    },
-    {
-      G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
-      NULL, "<INPUT FILE> <OUTPUT FILE>"
-    },
-    {
-      NULL
-    }
-  };
-
-  // init
-  swfdec_init ();
-
-  // read command line params
-  context = g_option_context_new ("Run a Flash file trying to crash Swfdec");
-  g_option_context_add_main_entries (context, entries, NULL);
-
-  if (g_option_context_parse (context, &argc, &argv, &err) == FALSE) {
-    g_printerr ("Couldn't parse command-line options: %s\n", err->message);
-    g_error_free (err);
-    return 1;
-  }
-
-  if (filenames == NULL || g_strv_length (filenames) < 1) {
-    g_printerr ("At least one input filename is required\n");
-    return 1;
-  }
-
-  // make them milliseconds
-  play_per_file *= 1000;
-  max_per_file *= 1000;
-  max_per_advance *= 1000;
-
-  // create surface
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-  cr = cairo_create (surface);
-
-  aborts = FALSE;
-  for (i = 0; i < g_strv_length (filenames); i++)
-  {
-    glong played, advance, elapsed;
-
-    g_print ("Running: %s\n", filenames[i]);
-
-    // start timer
-    timer = g_timer_new ();
-
-    // create player
-    loader = swfdec_file_loader_new (filenames[i]);
-    player = swfdec_player_new (NULL);
-
-    if (loader->error) {
-      g_printerr ("Error loading %s: %s\n", filenames[i], loader->error);
-      g_object_unref (loader);
-      continue;
-    }
-
-    swfdec_player_set_loader (player, loader);
-
-    // loop until we have played what we wanted, or timelimit is hit
-    played = 0;
-    elapsed = 0;
-    while (played < play_per_file &&
-	!swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player)))
-    {
-      elapsed = (glong)(g_timer_elapsed (timer, NULL) * 1000);
-      if (elapsed >= max_per_file)
-	break;
-      swfdec_player_set_maximum_runtime (player,
-	  MIN (max_per_advance, max_per_file - elapsed));
-
-      advance = swfdec_player_get_next_event (player);
-      if (advance == -1)
-	break;
-      swfdec_player_advance (player, advance);
-
-      swfdec_player_render (player, cr, 0, 0, 0, 0);
-
-      played += advance;
-    }
-
-    if (elapsed >= max_per_file ||
-	swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player))) {
-      g_print ("Aborted: %s\n", filenames[i]);
-      aborts = TRUE;
-    } else {
-      g_print ("Finished: %s\n", filenames[i]);
-    }
-
-    // clean up
-    g_object_unref (player);
-    g_timer_destroy (timer);
-  }
-
-  cairo_destroy (cr);
-  cairo_surface_destroy (surface);
-
-  if (aborts) {
-    return 1;
-  } else {
-    return 0;
-  }
-}
diff --git a/test/dump.c b/test/dump.c
deleted file mode 100644
index efea56d..0000000
--- a/test/dump.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/* Swfdec
- * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
- *		 2005-2006 Eric Anholt <eric at anholt.net>
- *		 2006-2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * 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 <stdio.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <glib.h>
-#include <glib-object.h>
-#include <libswfdec/swfdec.h>
-#include <libswfdec/swfdec_button.h>
-#include <libswfdec/swfdec_text_field.h>
-#include <libswfdec/swfdec_font.h>
-#include <libswfdec/swfdec_image.h>
-#include <libswfdec/swfdec_movie.h>
-#include <libswfdec/swfdec_player_internal.h>
-#include <libswfdec/swfdec_sprite.h>
-#include <libswfdec/swfdec_shape.h>
-#include <libswfdec/swfdec_sound.h>
-#include <libswfdec/swfdec_swf_decoder.h>
-#include <libswfdec/swfdec_resource.h>
-#include <libswfdec/swfdec_tag.h>
-#include <libswfdec/swfdec_text.h>
-
-static gboolean verbose = FALSE;
-
-static const char *
-get_audio_format_name (guint codec)
-{
-  switch (codec) {
-    case SWFDEC_AUDIO_CODEC_ADPCM:
-      return "ADPCM";
-    case SWFDEC_AUDIO_CODEC_MP3:
-      return "MP3";
-    case SWFDEC_AUDIO_CODEC_UNCOMPRESSED:
-      return "uncompressed";
-    case SWFDEC_AUDIO_CODEC_NELLYMOSER:
-      return "Nellymoser";
-    default:
-      return "Unknown";
-  }
-}
-
-static void
-dump_sound (SwfdecSound *sound)
-{
-  g_print ("  codec: %s\n", get_audio_format_name (sound->codec));
-  if (verbose) {
-    g_print ("  format: %s\n", swfdec_audio_format_to_string (sound->format));
-    g_print ("  samples: %u (%gs)\n", sound->n_samples, 
-	(double) sound->n_samples / swfdec_audio_format_get_rate (sound->format));
-  }
-}
-
-static void
-dump_sprite (SwfdecSwfDecoder *dec, SwfdecSprite *s)
-{
-  if (!verbose) {
-    g_print ("  %u frames\n", s->n_frames);
-  } else {
-    guint i, j, tag;
-    SwfdecBuffer *buffer;
-    SwfdecSound *sound = NULL;
-
-    for (i = 0; i < s->n_frames; i++) {
-      SwfdecSpriteFrame *frame = &s->frames[i];
-      if (frame->sound_head != sound &&
-	  frame->sound_block != NULL) {
-	sound = frame->sound_head;
-	for (j = i; j < s->n_frames; j++) {
-	  SwfdecSpriteFrame *cur = &s->frames[i];
-	  if (cur->sound_head != sound)
-	    break;
-	}
-	if (sound)
-	  g_print ("   %4u -%4u  sound: %s %s\n", i, j, 
-	      get_audio_format_name (sound->codec),
-	      swfdec_audio_format_to_string (sound->format));
-      }
-    }
-
-    j = 0;
-    for (i = 0; ; i++) {
-      if (!swfdec_sprite_get_action (s, i, &tag, &buffer))
-	break;
-      switch (tag) {
-	case SWFDEC_TAG_DOACTION:
-	  g_print ("   %4u script\n", j);
-	  break;
-	case SWFDEC_TAG_PLACEOBJECT2:
-	case SWFDEC_TAG_PLACEOBJECT3:
-	  {
-	    SwfdecBits bits;
-	    gboolean has_char, is_move;
-	    guint depth;
-
-	    swfdec_bits_init (&bits, buffer);
-	    swfdec_bits_getbits (&bits, 6);
-	    has_char = swfdec_bits_getbit (&bits);
-	    is_move = swfdec_bits_getbit (&bits);
-	    if (tag == SWFDEC_TAG_PLACEOBJECT3)
-	      swfdec_bits_get_u8 (&bits);
-	    depth = swfdec_bits_get_u16 (&bits);
-	    g_print ("   %4u %5u %s", j, depth, is_move ? "move" : "place");
-	    if (has_char) {
-	      SwfdecCharacter *c;
-	      c = swfdec_swf_decoder_get_character (dec, swfdec_bits_get_u16 (&bits));
-	      if (c)
-		g_print (" %s %u", G_OBJECT_TYPE_NAME (c), c->id);
-	    }
-	    g_print ("\n");
-	  }
-	  break;
-	case SWFDEC_TAG_REMOVEOBJECT:
-	case SWFDEC_TAG_REMOVEOBJECT2:
-	  {
-	    SwfdecBits bits;
-	    swfdec_bits_init (&bits, buffer);
-	    if (tag == SWFDEC_TAG_REMOVEOBJECT)
-	      swfdec_bits_get_u16 (&bits);
-	    g_print ("   %4u %5u remove\n", j, swfdec_bits_get_u16 (&bits));
-	  }
-	  break;
-	case SWFDEC_TAG_SHOWFRAME:
-	  j++;
-	  break;
-	case SWFDEC_TAG_STARTSOUND:
-	  /* FIXME add info about what sound etc */
-	  g_print ("   %4u start sound\n", j);
-	  break;
-	case SWFDEC_TAG_EXPORTASSETS:
-	  g_print ("   %4u export\n", j);
-	  break;
-	case SWFDEC_TAG_DOINITACTION:
-	  g_print ("   %4u init action\n", j);
-	  break;
-	default:
-	  g_assert_not_reached ();
-      }
-    }
-  }
-}
-
-static void
-dump_path (cairo_path_t *path)
-{
-  int i;
-  cairo_path_data_t *data = path->data;
-  const char *name;
-
-  for (i = 0; i < path->num_data; i++) {
-    name = NULL;
-    switch (data[i].header.type) {
-      case CAIRO_PATH_CURVE_TO:
-	g_print ("      curve %g %g (%g %g . %g %g)\n",
-	    data[i + 3].point.x, data[i + 3].point.y,
-	    data[i + 1].point.x, data[i + 1].point.y,
-	    data[i + 2].point.x, data[i + 2].point.y);
-	i += 3;
-	break;
-      case CAIRO_PATH_LINE_TO:
-	name = "line ";
-      case CAIRO_PATH_MOVE_TO:
-	if (!name)
-	  name = "move ";
-	i++;
-	g_print ("      %s %g %g\n", name, data[i].point.x, data[i].point.y);
-	break;
-      case CAIRO_PATH_CLOSE_PATH:
-	g_print ("      close\n");
-	break;
-      default:
-	g_assert_not_reached ();
-	break;
-    }
-  }
-}
-
-static void
-dump_shape (SwfdecShape *shape)
-{
-  GSList *walk;
-
-  for (walk = shape->draws; walk; walk = walk->next) {
-    if (SWFDEC_IS_PATTERN (walk->data)) {
-      SwfdecPattern *pattern = walk->data;
-      char *str = swfdec_pattern_to_string (pattern);
-      g_print ("%s\n", str);
-      g_free (str);
-      if (verbose) {
-	g_print ("        %g %g  %g %g  %g %g\n", 
-	    pattern->start_transform.xx, pattern->start_transform.xy,
-	    pattern->start_transform.yx, pattern->start_transform.yy,
-	    pattern->start_transform.x0, pattern->start_transform.y0);
-      }
-    } else if (SWFDEC_IS_STROKE (walk->data)) {
-      SwfdecStroke *line = walk->data;
-      g_print ("line (width %u, color #%08X)\n", line->start_width, line->start_color);
-    } else {
-      g_print ("not filled\n");
-    }
-    if (verbose) {
-      dump_path (&SWFDEC_DRAW (walk->data)->path);
-    }
-  }
-}
-
-static void
-dump_text_field (SwfdecTextField *text)
-{
-  g_print ("  %s\n", text->input ? text->input : "");
-  if (verbose) {
-    if (text->variable)
-      g_print ("  variable %s\n", text->variable);
-    else
-      g_print ("  no variable\n");
-  }
-}
-
-static void
-dump_text (SwfdecText *text)
-{
-  guint i;
-  gunichar2 uni[text->glyphs->len];
-  char *s;
-
-  for (i = 0; i < text->glyphs->len; i++) {
-    SwfdecTextGlyph *glyph = &g_array_index (text->glyphs, SwfdecTextGlyph, i);
-    uni[i] = g_array_index (glyph->font->glyphs, SwfdecFontEntry, glyph->glyph).value;
-    if (uni[i] == 0)
-      goto fallback;
-  }
-  s = g_utf16_to_utf8 (uni, text->glyphs->len, NULL, NULL, NULL);
-  if (s == NULL)
-    goto fallback;
-  g_print ("  text: %s\n", s);
-  g_free (s);
-  return;
-
-fallback:
-  g_print ("  %u characters\n", text->glyphs->len);
-}
-
-static void
-dump_font (SwfdecFont *font)
-{
-  unsigned int i;
-  if (font->name)
-    g_print ("  %s\n", font->name);
-  g_print ("  %u characters\n", font->glyphs->len);
-  if (verbose) {
-    for (i = 0; i < font->glyphs->len; i++) {
-      gunichar2 c = g_array_index (font->glyphs, SwfdecFontEntry, i).value;
-      char *s;
-      if (c == 0 || (s = g_utf16_to_utf8 (&c, 1, NULL, NULL, NULL)) == NULL) {
-	g_print (" ");
-      } else {
-	g_print ("%s ", s);
-	g_free (s);
-      }
-    }
-    g_print ("\n");
-  }
-}
-
-static void
-dump_button (SwfdecButton *button)
-{
-}
-
-static const char *
-get_image_type_name (SwfdecImageType type)
-{
-  switch (type) {
-    case SWFDEC_IMAGE_TYPE_JPEG:
-      return "JPEG with global table";
-    case SWFDEC_IMAGE_TYPE_JPEG2:
-      return "JPEG";
-    case SWFDEC_IMAGE_TYPE_JPEG3:
-      return "JPEG with alpha";
-    case SWFDEC_IMAGE_TYPE_LOSSLESS:
-      return "lossless";
-    case SWFDEC_IMAGE_TYPE_LOSSLESS2:
-      return "lossless with alpha";
-    case SWFDEC_IMAGE_TYPE_PNG:
-      return "PNG";
-    case SWFDEC_IMAGE_TYPE_UNKNOWN:
-    default:
-      g_assert_not_reached ();
-      return "Unknown";
-  }
-}
-
-static void
-dump_image (SwfdecImage *image)
-{
-  cairo_surface_destroy (swfdec_image_create_surface (image));
-  g_print ("  %s %u x %u\n", get_image_type_name (image->type),
-      image->width, image->height);
-}
-
-static void 
-dump_object (gpointer value, gpointer dec)
-{
-  SwfdecCharacter *c = value;
-
-  g_print ("%d: %s\n", c->id, G_OBJECT_TYPE_NAME (c));
-  if (verbose && SWFDEC_IS_GRAPHIC (c)) {
-    SwfdecGraphic *graphic = SWFDEC_GRAPHIC (c);
-    g_print ("  extents: %g %g  %g %g\n", graphic->extents.x0, graphic->extents.y0,
-	graphic->extents.x1, graphic->extents.y1);
-  }
-  if (SWFDEC_IS_IMAGE (c)) {
-    dump_image (SWFDEC_IMAGE (c));
-  }
-  if (SWFDEC_IS_SPRITE (c)) {
-    dump_sprite (dec, SWFDEC_SPRITE (c));
-  }
-  if (SWFDEC_IS_SHAPE(c)) {
-    dump_shape(SWFDEC_SHAPE(c));
-  }
-  if (SWFDEC_IS_TEXT (c)) {
-    dump_text (SWFDEC_TEXT (c));
-  }
-  if (SWFDEC_IS_TEXT_FIELD (c)) {
-    dump_text_field (SWFDEC_TEXT_FIELD (c));
-  }
-  if (SWFDEC_IS_FONT (c)) {
-    dump_font (SWFDEC_FONT (c));
-  }
-  if (SWFDEC_IS_BUTTON (c)) {
-    dump_button (SWFDEC_BUTTON (c));
-  }
-  if (SWFDEC_IS_SOUND (c)) {
-    dump_sound (SWFDEC_SOUND (c));
-  }
-}
-
-static void 
-enqueue (gpointer key, gpointer value, gpointer listp)
-{
-  GList **list = listp;
-
-  *list = g_list_prepend (*list, value);
-}
-
-static int
-sort_by_id (gconstpointer a, gconstpointer b)
-{
-  if (SWFDEC_CHARACTER (a)->id < SWFDEC_CHARACTER (b)->id)
-    return -1;
-  return 1;
-}
-
-int
-main (int argc, char *argv[])
-{
-  SwfdecSwfDecoder *s;
-  SwfdecPlayer *player;
-  GError *error = NULL;
-  GOptionEntry options[] = {
-    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "bew verbose", NULL },
-    { NULL }
-  };
-  GOptionContext *ctx;
-  GList *list = NULL;
-
-  ctx = g_option_context_new ("");
-  g_option_context_add_main_entries (ctx, options, "options");
-  g_option_context_parse (ctx, &argc, &argv, &error);
-  g_option_context_free (ctx);
-  if (error) {
-    g_printerr ("Error parsing command line arguments: %s\n", error->message);
-    g_error_free (error);
-    return 1;
-  }
-
-  swfdec_init();
-
-  if(argc < 2){
-    g_print ("usage: %s [OPTIONS] file\n", argv[0]);
-    return 0;
-  }
-
-  player = swfdec_player_new_from_file (argv[1]);
-  if (player->priv->resource->loader->error) {
-    g_printerr ("Couldn't open file \"%s\": %s\n", argv[1], player->priv->resource->loader->error);
-    g_object_unref (player);
-    return 1;
-  }
-  /* FIXME: HACK! */
-  swfdec_player_advance (player, 0);
-  if (!swfdec_player_is_initialized (player)) {
-    g_printerr ("File \"%s\" is not a SWF file\n", argv[1]);
-    g_object_unref (player);
-    player = NULL;
-    return 1;
-  }
-  s = (SwfdecSwfDecoder *) SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder;
-  /* FIXME: can happen after a _root.loadMovie() call */
-  if (!SWFDEC_IS_SWF_DECODER (s)) {
-    g_printerr ("Movie already unloaded from \"%s\"\n", argv[1]);
-    g_object_unref (player);
-    player = NULL;
-    return 1;
-  }
-
-  g_print ("file:\n");
-  g_print ("  version: %d\n", s->version);
-  g_print ("  rate   : %g fps\n",  SWFDEC_DECODER (s)->rate / 256.0);
-  g_print ("  size   : %ux%u pixels\n", SWFDEC_DECODER (s)->width, SWFDEC_DECODER (s)->height);
-  g_print ("objects:\n");
-  g_hash_table_foreach (s->characters, enqueue, &list);
-  list = g_list_sort (list, sort_by_id);
-  g_list_foreach (list, dump_object, s);
-  g_list_free (list);
-
-  g_print ("main sprite:\n");
-  dump_sprite (s, s->main_sprite);
-  g_object_unref (player);
-  s = NULL;
-  player = NULL;
-
-  return 0;
-}
-
diff --git a/test/swfdec-extract.c b/test/swfdec-extract.c
deleted file mode 100644
index 3edfd25..0000000
--- a/test/swfdec-extract.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006 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 <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <cairo.h>
-#ifdef CAIRO_HAS_SVG_SURFACE
-#  include <cairo-svg.h>
-#endif
-#ifdef CAIRO_HAS_PDF_SURFACE
-#  include <cairo-pdf.h>
-#endif
-#include <libswfdec/swfdec.h>
-#include <libswfdec/swfdec_audio_stream.h>
-#include <libswfdec/swfdec_button.h>
-#include <libswfdec/swfdec_graphic.h>
-#include <libswfdec/swfdec_image.h>
-#include <libswfdec/swfdec_player_internal.h>
-#include <libswfdec/swfdec_sound.h>
-#include <libswfdec/swfdec_sprite.h>
-#include <libswfdec/swfdec_sprite_movie.h>
-#include <libswfdec/swfdec_swf_decoder.h>
-#include <libswfdec/swfdec_resource.h>
-
-static SwfdecBuffer *
-encode_wav (SwfdecBuffer *buffer, SwfdecAudioFormat format)
-{
-  SwfdecBuffer *wav = swfdec_buffer_new_and_alloc (buffer->length + 44);
-  unsigned char *data;
-  guint i;
-
-  data = wav->data;
-  /* FIXME: too much magic in this memmove */
-  memmove (data, "RIFF----WAVEfmt \020\0\0\0"
-		 "\001\0ccRRRRbbbbAAbbdata", 40);
-  *(guint32 *) (void *) &data[4] = GUINT32_TO_LE (buffer->length + 36);
-  *(guint16 *) (void *) &data[22] = GUINT16_TO_LE (swfdec_audio_format_get_channels (format));
-  *(guint32 *) (void *) &data[24] = GUINT32_TO_LE (swfdec_audio_format_get_rate (format));
-  /* bits per sample */
-  i = swfdec_audio_format_is_16bit (format) ? 2 : 1;
-  *(guint16 *) (void *) &data[34] = GUINT16_TO_LE (i * 8);
-  /* block align */
-  i *= swfdec_audio_format_get_channels (format);
-  *(guint16 *) (void *) &data[32] = GUINT16_TO_LE (i);
-  /* bytes per second */
-  i *= swfdec_audio_format_get_rate (format);
-  *(guint32 *) (void *) &data[28] = GUINT32_TO_LE (i);
-  *(guint32 *) (void *) &data[40] = GUINT32_TO_LE (buffer->length);
-  data += 44;
-  if (swfdec_audio_format_is_16bit (format)) {
-    for (i = 0; i < buffer->length; i += 2) {
-      *(gint16 *) (void *) (data + i) = GINT16_TO_LE (*(gint16* ) (void *) (buffer->data + i));
-    }
-  } else {
-    memcpy (data, buffer->data, buffer->length);
-  }
-  return wav;
-}
-
-static gboolean
-export_sound (SwfdecSound *sound, const char *filename)
-{
-  GError *error = NULL;
-  SwfdecBuffer *wav, *buffer;
-  SwfdecAudioFormat format;
-
-  /* try to render the sound, that should decode it. */
-  buffer = swfdec_sound_get_decoded (sound, &format);
-  if (buffer == NULL) {
-    g_printerr ("Couldn't decode sound. For extraction of streams extract the sprite.\n");
-    return FALSE;
-  }
-  wav = encode_wav (buffer, format);
-  if (!g_file_set_contents (filename, (char *) wav->data, 
-	wav->length, &error)) {
-    g_printerr ("Couldn't save sound to file \"%s\": %s\n", filename, error->message);
-    swfdec_buffer_unref (wav);
-    g_error_free (error);
-    return FALSE;
-  }
-  swfdec_buffer_unref (wav);
-  return TRUE;
-}
-
-static gboolean
-export_sprite_sound (SwfdecSprite *sprite, const char *filename)
-{
-  GError *error = NULL;
-  guint i, depth;
-  SwfdecAudio *audio;
-  SwfdecBufferQueue *queue;
-  SwfdecBuffer *buffer, *wav;
-
-  for (i = 0; i < sprite->n_frames; i++) {
-    if (sprite->frames[i].sound_head)
-      break;
-  }
-  if (i >= sprite->n_frames) {
-    g_printerr ("No sound in sprite %u\n", SWFDEC_CHARACTER (sprite)->id);
-    return FALSE;
-  }
-  audio = swfdec_audio_stream_new (NULL, sprite, i);
-  i = 4096;
-  queue = swfdec_buffer_queue_new ();
-  while (i > 0) {
-    buffer = swfdec_buffer_new ();
-    buffer->data = g_malloc0 (i * 4);
-    buffer->length = i * 4;
-#if 0
-    if (i > 1234) {
-      swfdec_audio_render (audio, (gint16 *) buffer->data, 0, 1234);
-      swfdec_audio_render (audio, (gint16 *) buffer->data + 2468, 1234, i - 1234);
-    } else
-#endif
-    {
-      swfdec_audio_render (audio, (gint16 *) (void *) buffer->data, 0, i);
-    }
-    i = swfdec_audio_iterate (audio, i);
-    i = MIN (i, 4096);
-    swfdec_buffer_queue_push (queue, buffer);
-  }
-  depth = swfdec_buffer_queue_get_depth (queue);
-  if (depth == 0) {
-    swfdec_buffer_queue_unref (queue);
-    g_printerr ("Sprite contains no sound\n");
-    return FALSE;
-  }
-  buffer = swfdec_buffer_queue_pull (queue, depth);
-  swfdec_buffer_queue_unref (queue);
-  wav = encode_wav (buffer, swfdec_audio_format_new (44100, 2, TRUE));
-  swfdec_buffer_unref (buffer);
-  if (!g_file_set_contents (filename, (char *) wav->data, 
-	wav->length, &error)) {
-    g_printerr ("Couldn't save sound to file \"%s\": %s\n", filename, error->message);
-    swfdec_buffer_unref (wav);
-    g_error_free (error);
-    return FALSE;
-  }
-  swfdec_buffer_unref (wav);
-  return TRUE;
-}
-
-static cairo_surface_t *
-surface_create_for_filename (const char *filename, int width, int height)
-{
-  guint len = strlen (filename);
-  cairo_surface_t *surface;
-  if (FALSE) {
-#ifdef CAIRO_HAS_PDF_SURFACE
-  } else if (len >= 3 && g_ascii_strcasecmp (filename + len - 3, "pdf") == 0) {
-    surface = cairo_pdf_surface_create (filename, width, height);
-#endif
-#ifdef CAIRO_HAS_SVG_SURFACE
-  } else if (len >= 3 && g_ascii_strcasecmp (filename + len - 3, "svg") == 0) {
-    surface = cairo_svg_surface_create (filename, width, height);
-#endif
-  } else {
-    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-  }
-  return surface;
-}
-
-static gboolean
-surface_destroy_for_type (cairo_surface_t *surface, const char *filename)
-{
-  if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) {
-    cairo_status_t status = cairo_surface_write_to_png (surface, filename);
-    if (status != CAIRO_STATUS_SUCCESS) {
-      g_printerr ("Error saving file: %s\n", cairo_status_to_string (status));
-      cairo_surface_destroy (surface);
-      return FALSE;
-    }
-  }
-  cairo_surface_destroy (surface);
-  return TRUE;
-}
-
-static gboolean
-export_graphic (SwfdecGraphic *graphic, const char *filename)
-{
-  cairo_surface_t *surface;
-  cairo_t *cr;
-  guint width, height;
-  const SwfdecColorTransform trans = { 256, 0, 256, 0, 256, 0, 256, 0 };
-
-  if (SWFDEC_IS_SPRITE (graphic)) {
-    g_printerr ("Sprites can not be exported\n");
-    return FALSE;
-  }
-  if (SWFDEC_IS_BUTTON (graphic)) {
-    g_printerr ("Buttons can not be exported\n");
-    return FALSE;
-  }
-  width = ceil (graphic->extents.x1 / SWFDEC_TWIPS_SCALE_FACTOR) 
-    - floor (graphic->extents.x0 / SWFDEC_TWIPS_SCALE_FACTOR);
-  height = ceil (graphic->extents.y1 / SWFDEC_TWIPS_SCALE_FACTOR) 
-    - floor (graphic->extents.y0 / SWFDEC_TWIPS_SCALE_FACTOR);
-  surface = surface_create_for_filename (filename, width, height);
-  cr = cairo_create (surface);
-  cairo_translate (cr, - floor (graphic->extents.x0 / SWFDEC_TWIPS_SCALE_FACTOR),
-    - floor (graphic->extents.y0 / SWFDEC_TWIPS_SCALE_FACTOR));
-  cairo_scale (cr, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR);
-  swfdec_graphic_render (graphic, cr, &trans, &graphic->extents);
-  cairo_show_page (cr);
-  cairo_destroy (cr);
-  return surface_destroy_for_type (surface, filename);
-}
-
-static gboolean
-export_image (SwfdecImage *image, const char *filename)
-{
-  cairo_surface_t *surface = swfdec_image_create_surface (image);
-
-  if (surface == NULL)
-    return FALSE;
-  return surface_destroy_for_type (surface, filename);
-}
-
-static void
-usage (const char *app)
-{
-  g_print ("usage: %s SWFFILE ID OUTFILE\n\n", app);
-}
-
-int
-main (int argc, char *argv[])
-{
-  SwfdecCharacter *character;
-  int ret = 0;
-  SwfdecPlayer *player;
-  glong id;
-
-  swfdec_init ();
-
-  if (argc != 4) {
-    usage (argv[0]);
-    return 0;
-  }
-
-  player = swfdec_player_new_from_file (argv[1]);
-  /* FIXME: HACK! */
-  swfdec_player_advance (player, 0);
-  if (!SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data)) {
-    g_printerr ("Error parsing file \"%s\"\n", argv[1]);
-    g_object_unref (player);
-    player = NULL;
-    return 1;
-  }
-  id = strtol (argv[2], NULL, 0);
-  if (id >= 0) {
-    character = swfdec_swf_decoder_get_character (
-	SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder),
-	id);
-  } else {
-    character = SWFDEC_CHARACTER (SWFDEC_SWF_DECODER (
-	  SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder)->main_sprite);
-  }
-  if (SWFDEC_IS_SPRITE (character)) {
-    if (!export_sprite_sound (SWFDEC_SPRITE (character), argv[3]))
-      ret = 1;
-  } else if (SWFDEC_IS_SOUND (character)) {
-    if (!export_sound (SWFDEC_SOUND (character), argv[3]))
-      ret = 1;
-  } else if (SWFDEC_IS_GRAPHIC (character)) {
-    if (!export_graphic (SWFDEC_GRAPHIC (character), argv[3]))
-      ret = 1;
-  } else if (SWFDEC_IS_IMAGE (character)) {
-    if (!export_image (SWFDEC_IMAGE (character), argv[3]))
-      ret = 1;
-  } else {
-    g_printerr ("id %ld does not specify an exportable object\n", id);
-    ret = 1;
-  }
-
-  g_object_unref (player);
-  player = NULL;
-
-  return ret;
-}
-
diff --git a/test/swfdec_out.c b/test/swfdec_out.c
deleted file mode 100644
index ecf5a83..0000000
--- a/test/swfdec_out.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/* 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_get_bits (SwfdecOut *out)
-{
-  g_return_val_if_fail (out != NULL, 0);
-
-  return (out->ptr - out->data) * 8 + out->idx;
-}
-
-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_data (SwfdecOut *out, const guint8 *data, guint length)
-{
-  g_return_if_fail (out != NULL);
-
-  swfdec_out_prepare_bytes (out, length);
-  memcpy (out->ptr, data, length);
-  out->ptr += length;
-}
-
-void
-swfdec_out_put_buffer (SwfdecOut *out, SwfdecBuffer *buffer)
-{
-  g_return_if_fail (out != NULL);
-
-  swfdec_out_prepare_bytes (out, buffer->length);
-  memcpy (out->ptr, buffer->data, buffer->length);
-  out->ptr += buffer->length;
-}
-
-void
-swfdec_out_put_u8 (SwfdecOut *out, guint i)
-{
-  g_return_if_fail (i <= G_MAXUINT8);
-
-  swfdec_out_prepare_bytes (out, 1);
-  *out->ptr = i;
-  out->ptr++;
-}
-
-void
-swfdec_out_put_u16 (SwfdecOut *out, guint i)
-{
-  g_return_if_fail (i <= G_MAXUINT16);
-
-  swfdec_out_prepare_bytes (out, 2);
-  *(guint16 *)out->ptr = GUINT16_TO_LE (i);
-  out->ptr += 2;
-}
-
-void
-swfdec_out_put_u32 (SwfdecOut *out, guint i)
-{
-  g_return_if_fail (i <= G_MAXUINT32);
-
-  swfdec_out_prepare_bytes (out, 4);
-  *(guint32 *)out->ptr = GUINT32_TO_LE (i);
-  out->ptr += 4;
-}
-
-void
-swfdec_out_put_bit (SwfdecOut *out, gboolean bit)
-{
-  g_return_if_fail (out != NULL);
-
-  swfdec_out_put_bits (out, bit ? 1 : 0, 1);
-}
-
-void
-swfdec_out_put_bits (SwfdecOut *out, guint bits, guint n_bits)
-{
-  g_return_if_fail (out != NULL);
-
-  swfdec_out_ensure_bits (out, n_bits);
-
-  /* FIXME: implement this less braindead */
-  while (n_bits) {
-    guint bits_now = MIN (n_bits, 8 - out->idx);
-    guint value = bits >> (n_bits - bits_now);
-
-    /* clear data if necessary */
-    if (out->idx == 0)
-      *out->ptr = 0;
-    value &= (1 << bits_now) - 1;
-    value <<= 8 - out->idx - bits_now;
-    *out->ptr |= value;
-    out->idx += bits_now;
-    g_assert (out->idx <= 8);
-    if (out->idx == 8) {
-      out->ptr ++;
-      out->idx = 0;
-    }
-    n_bits -= bits_now;
-  }
-}
-
-void
-swfdec_out_put_sbits (SwfdecOut *out, int bits, guint n_bits)
-{
-  g_return_if_fail (out != NULL);
-  swfdec_out_put_bits (out, bits, n_bits);
-}
-
-void
-swfdec_out_put_string (SwfdecOut *out, const char *s)
-{
-  guint len;
-
-  g_return_if_fail (out != NULL);
-  g_return_if_fail (s != NULL);
-
-  len = strlen (s) + 1;
-
-  swfdec_out_prepare_bytes (out, len);
-  memcpy (out->ptr, s, len);
-  out->ptr += len;
-}
-
-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, const SwfdecRect *rect)
-{
-  int x0, x1, y0, y1;
-  guint req, tmp;
-
-  g_return_if_fail (out != NULL);
-  g_return_if_fail (rect != NULL);
-
-  x0 = rect->x0;
-  y0 = rect->y0;
-  x1 = rect->x1;
-  y1 = rect->y1;
-  req = swfdec_out_sbits_required (x0);
-  tmp = swfdec_out_sbits_required (y0);
-  req = MAX (req, tmp);
-  tmp = swfdec_out_sbits_required (x1);
-  req = MAX (req, tmp);
-  tmp = swfdec_out_sbits_required (y1);
-  req = MAX (req, tmp);
-  swfdec_out_syncbits (out);
-  swfdec_out_put_bits (out, req, 5);
-  swfdec_out_put_sbits (out, x0, req);
-  swfdec_out_put_sbits (out, x1, req);
-  swfdec_out_put_sbits (out, y0, req);
-  swfdec_out_put_sbits (out, y1, req);
-  swfdec_out_syncbits (out);
-}
-
-void
-swfdec_out_put_matrix (SwfdecOut *out, const cairo_matrix_t *matrix)
-{
-  int x, y;
-  unsigned int xbits, ybits;
-
-  if (matrix->xx != 1.0 || matrix->yy != 1.0) {
-    swfdec_out_put_bit (out, 1);
-    x = SWFDEC_DOUBLE_TO_FIXED (matrix->xx);
-    y = SWFDEC_DOUBLE_TO_FIXED (matrix->yy);
-    xbits = swfdec_out_sbits_required (x);
-    ybits = swfdec_out_sbits_required (y);
-    xbits = MAX (xbits, ybits);
-    swfdec_out_put_bits (out, xbits, 5);
-    swfdec_out_put_sbits (out, x, xbits);
-    swfdec_out_put_sbits (out, y, xbits);
-  } else {
-    swfdec_out_put_bit (out, 0);
-  }
-  if (matrix->xy != 0.0 || matrix->yx != 0.0) {
-    swfdec_out_put_bit (out, 1);
-    x = SWFDEC_DOUBLE_TO_FIXED (matrix->yx);
-    y = SWFDEC_DOUBLE_TO_FIXED (matrix->xy);
-    xbits = swfdec_out_sbits_required (x);
-    ybits = swfdec_out_sbits_required (y);
-    xbits = MAX (xbits, ybits);
-    swfdec_out_put_bits (out, xbits, 5);
-    swfdec_out_put_sbits (out, x, xbits);
-    swfdec_out_put_sbits (out, y, xbits);
-  } else {
-    swfdec_out_put_bit (out, 0);
-  }
-  x = matrix->x0;
-  y = matrix->y0;
-  xbits = swfdec_out_sbits_required (x);
-  ybits = swfdec_out_sbits_required (y);
-  xbits = MAX (xbits, ybits);
-  swfdec_out_put_bits (out, xbits, 5);
-  swfdec_out_put_sbits (out, x, xbits);
-  swfdec_out_put_sbits (out, y, xbits);
-  swfdec_out_syncbits (out);
-}
-
-void
-swfdec_out_put_color_transform (SwfdecOut *out, const SwfdecColorTransform *trans)
-{
-  gboolean has_add, has_mult;
-  unsigned int n_bits, tmp;
-
-  has_mult = trans->ra != 256 || trans->ga != 256 || trans->ba != 256 || trans->aa != 256;
-  has_add = trans->rb != 0 || trans->gb != 0 || trans->bb != 0 || trans->ab != 0;
-  if (has_mult) {
-    n_bits = swfdec_out_sbits_required (trans->ra);
-    tmp = swfdec_out_sbits_required (trans->ga);
-    n_bits = MAX (tmp, n_bits);
-    tmp = swfdec_out_sbits_required (trans->ba);
-    n_bits = MAX (tmp, n_bits);
-    tmp = swfdec_out_sbits_required (trans->aa);
-    n_bits = MAX (tmp, n_bits);
-  } else {
-    n_bits = 0;
-  }
-  if (has_add) {
-    tmp = swfdec_out_sbits_required (trans->rb);
-    n_bits = MAX (tmp, n_bits);
-    tmp = swfdec_out_sbits_required (trans->gb);
-    n_bits = MAX (tmp, n_bits);
-    tmp = swfdec_out_sbits_required (trans->bb);
-    n_bits = MAX (tmp, n_bits);
-    tmp = swfdec_out_sbits_required (trans->ab);
-    n_bits = MAX (tmp, n_bits);
-  }
-  if (n_bits >= (1 << 4))
-    n_bits = (1 << 4) - 1;
-  swfdec_out_put_bit (out, has_add);
-  swfdec_out_put_bit (out, has_mult);
-  swfdec_out_put_bits (out, n_bits, 4);
-  if (has_mult) {
-    swfdec_out_put_sbits (out, trans->ra, n_bits);
-    swfdec_out_put_sbits (out, trans->ga, n_bits);
-    swfdec_out_put_sbits (out, trans->ba, n_bits);
-    swfdec_out_put_sbits (out, trans->aa, n_bits);
-  }
-  if (has_add) {
-    swfdec_out_put_sbits (out, trans->rb, n_bits);
-    swfdec_out_put_sbits (out, trans->gb, n_bits);
-    swfdec_out_put_sbits (out, trans->bb, n_bits);
-    swfdec_out_put_sbits (out, trans->ab, n_bits);
-  }
-  swfdec_out_syncbits (out);
-}
-
-void
-swfdec_out_put_rgb (SwfdecOut *out, SwfdecColor color)
-{
-  g_return_if_fail (out != NULL);
-
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_R (color));
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_G (color));
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_B (color));
-}
-
-void
-swfdec_out_put_rgba (SwfdecOut *out, SwfdecColor color)
-{
-  g_return_if_fail (out != NULL);
-
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_R (color));
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_G (color));
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_B (color));
-  swfdec_out_put_u8 (out, SWFDEC_COLOR_A (color));
-}
-
diff --git a/test/swfdec_out.h b/test/swfdec_out.h
deleted file mode 100644
index e343f9d..0000000
--- a/test/swfdec_out.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* 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_color.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_get_bits		(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_data		(SwfdecOut *		out,
-						 const guint8 *		data,
-						 guint			length);
-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_string		(SwfdecOut *		out,
-						 const char *		s);
-
-void		swfdec_out_put_rgb		(SwfdecOut *		out,
-						 SwfdecColor		color);
-void		swfdec_out_put_rgba		(SwfdecOut *		out,
-						 SwfdecColor		color);
-void		swfdec_out_put_rect		(SwfdecOut *		out,
-						 const SwfdecRect *	rect);
-void		swfdec_out_put_matrix		(SwfdecOut *		out,
-						 const cairo_matrix_t *	matrix);
-void		swfdec_out_put_color_transform	(SwfdecOut *		out,
-						 const SwfdecColorTransform *trans);
-
-
-G_END_DECLS
-
-#endif
diff --git a/test/swfedit.c b/test/swfedit.c
deleted file mode 100644
index 24f2980..0000000
--- a/test/swfedit.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gtk/gtk.h>
-#include "swfedit_file.h"
-
-static void
-save (GtkButton *button, SwfeditFile *file)
-{
-  GtkWidget *dialog;
-  GError *error = NULL;
-
-  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_REJECT,
-      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 
-      NULL);
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
-  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_ACCEPT) {
-    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
-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_iter (SWFEDIT_TOKEN (file), &iter, new_text);
-}
-
-static gboolean
-open_window (char *filename)
-{
-  SwfeditFile *file;
-  GtkWidget *window, *scroll, *box, *button, *treeview;
-  GError *error = NULL;
-  GtkTreeViewColumn *column;
-  GtkCellRenderer *renderer;
-  char *basename;
-
-  file = swfedit_file_new (filename, &error);
-  if (file == NULL) {
-    g_printerr ("Error opening file %s: %s\n", filename, error->message);
-    g_error_free (error);
-    return FALSE;
-  }
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  basename = g_path_get_basename (filename);
-  if (basename) {
-    gtk_window_set_title (GTK_WINDOW (window), basename);
-    g_free (basename);
-  }
-  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_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);
-
-  renderer = gtk_cell_renderer_text_new ();
-  column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
-    "text", SWFEDIT_COLUMN_NAME, "sensitive", SWFEDIT_COLUMN_VALUE_EDITABLE, NULL);
-  gtk_tree_view_column_set_resizable (column, TRUE);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
-
-  renderer = gtk_cell_renderer_text_new ();
-  g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
-  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, 
-    "sensitive", SWFEDIT_COLUMN_VALUE_EDITABLE, NULL);
-  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;
-}
-
-int
-main (int argc, char **argv)
-{
-  gtk_init (&argc, &argv);
-
-  if (argc <= 1) {
-    g_print ("Usage: %s FILENAME\n", argv[0]);
-    return 1;
-  }
-  if (open_window (argv[1])) {
-    gtk_main ();
-    return 0;
-  } else {
-    return 1;
-  }
-}
-
diff --git a/test/swfedit_file.c b/test/swfedit_file.c
deleted file mode 100644
index e257010..0000000
--- a/test/swfedit_file.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <zlib.h>
-
-#include "libswfdec/swfdec_bits.h"
-#include "libswfdec/swfdec_buffer.h"
-#include "libswfdec/swfdec_debug.h"
-#include "libswfdec/swfdec_swf_decoder.h"
-#include "swfdec_out.h"
-#include "swfedit_file.h"
-#include "swfedit_tag.h"
-
-G_DEFINE_TYPE (SwfeditFile, swfedit_file, SWFEDIT_TYPE_TOKEN)
-
-static void
-swfedit_file_dispose (GObject *object)
-{
-  SwfeditFile *file = SWFEDIT_FILE (object);
-
-  g_free (file->filename);
-
-  G_OBJECT_CLASS (swfedit_file_parent_class)->dispose (object);
-}
-
-static void *
-zalloc (void *opaque, unsigned int items, unsigned int size)
-{
-  return g_malloc (items * size);
-}
-
-static void
-zfree (void *opaque, void *addr)
-{
-  g_free (addr);
-}
-
-static SwfdecBuffer *
-swfenc_file_inflate (SwfdecBits *bits, guint size)
-{
-  SwfdecBuffer *decoded, *encoded;
-  z_stream z;
-  int ret;
-
-  encoded = swfdec_bits_get_buffer (bits, -1);
-  if (encoded == NULL)
-    return NULL;
-  decoded = swfdec_buffer_new_and_alloc (size);
-  z.zalloc = zalloc;
-  z.zfree = zfree;
-  z.opaque = NULL;
-  z.next_in = encoded->data;
-  z.avail_in = encoded->length;
-  z.next_out = decoded->data;
-  z.avail_out = decoded->length;
-  ret = inflateInit (&z);
-  SWFDEC_DEBUG ("inflateInit returned %d", ret);
-  if (ret >= Z_OK) {
-    ret = inflate (&z, Z_SYNC_FLUSH);
-    SWFDEC_DEBUG ("inflate returned %d", ret);
-  }
-  inflateEnd (&z);
-  swfdec_buffer_unref (encoded);
-  if (ret < Z_OK) {
-    swfdec_buffer_unref (decoded);
-    return NULL;
-  }
-  return decoded;
-}
-
-static SwfdecBuffer *
-swf_parse_header1 (SwfeditFile *file, SwfdecBits *bits, GError **error)
-{
-  guint sig1, sig2, sig3, bytes_total;
-
-  sig1 = swfdec_bits_get_u8 (bits);
-  sig2 = swfdec_bits_get_u8 (bits);
-  sig3 = swfdec_bits_get_u8 (bits);
-  if ((sig1 != 'F' && sig1 != 'C') || sig2 != 'W' || sig3 != 'S') {
-    g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-	"This is not a SWF file");
-    return NULL;
-  }
-
-  swfedit_token_add (SWFEDIT_TOKEN (file), "version", SWFEDIT_TOKEN_UINT8, 
-      GUINT_TO_POINTER (swfdec_bits_get_u8 (bits)));
-  bytes_total = swfdec_bits_get_u32 (bits) - 8;
-
-  if (sig1 == 'C') {
-    /* compressed */
-    SwfdecBuffer *ret = swfenc_file_inflate (bits, bytes_total);
-    if (ret == NULL)
-      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-	  "Unable to uncompress file");
-    return ret;
-  } else {
-    SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, bytes_total);
-    if (ret == NULL)
-      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-	  "File too small");
-    return ret;
-  }
-}
-
-static void
-swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits)
-{
-  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rect", SWFEDIT_TOKEN_RECT, NULL);
-  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rate", SWFEDIT_TOKEN_UINT16, NULL);
-  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "frames", SWFEDIT_TOKEN_UINT16, NULL);
-}
-
-static gboolean
-swfedit_file_parse (SwfeditFile *file, SwfdecBits *bits, GError **error)
-{
-  SwfdecBuffer *next;
-  
-  next = swf_parse_header1 (file, bits, error);
-  if (next == NULL)
-    return FALSE;
-  swfdec_bits_init (bits, next);
-  swf_parse_header2 (file, bits);
-
-  while (swfdec_bits_left (bits)) {
-    guint x = swfdec_bits_get_u16 (bits);
-    G_GNUC_UNUSED guint tag = (x >> 6) & 0x3ff;
-    guint tag_len = x & 0x3f;
-    SwfdecBuffer *buffer;
-    SwfeditTag *item;
-
-    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
-      buffer = swfdec_buffer_new ();
-    if (buffer == NULL) {
-      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-	  "Invalid contents in file");
-      return FALSE;
-    }
-    item = swfedit_tag_new (SWFEDIT_TOKEN (file), tag, buffer);
-    swfedit_token_add (SWFEDIT_TOKEN (file), 
-	swfdec_swf_decoder_get_tag_name (tag), 
-	SWFEDIT_TOKEN_OBJECT, item);
-  }
-  swfdec_buffer_unref (next);
-  return TRUE;
-}
-
-static void
-swfedit_file_class_init (SwfeditFileClass *class)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-  object_class->dispose = swfedit_file_dispose;
-}
-
-static void
-swfedit_file_init (SwfeditFile *s)
-{
-}
-
-SwfeditFile *
-swfedit_file_new (const char *filename, GError **error)
-{
-  SwfeditFile *file;
-  SwfdecBuffer *buffer;
-  SwfdecBits bits;
-  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 = absolute;
-  if (!swfedit_file_parse (file, &bits, error)) {
-    swfdec_buffer_unref (buffer);
-    g_object_unref (file);
-    return NULL;
-  }
-  swfdec_buffer_unref (buffer);
-  return file;
-}
-
-static SwfdecBuffer *
-swfedit_file_write (SwfeditFile *file)
-{
-  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);
-  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_unref (queue);
-  return swfdec_out_close (out);
-}
-
-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;
-}
-
-guint
-swfedit_file_get_version (SwfeditFile *file)
-{
-  SwfeditTokenEntry *entry;
-
-  g_return_val_if_fail (SWFEDIT_FILE (file), 3);
-
-  entry = &g_array_index (SWFEDIT_TOKEN (file)->tokens, SwfeditTokenEntry, 0);
-  return GPOINTER_TO_UINT (entry->value);
-}
-
diff --git a/test/swfedit_file.h b/test/swfedit_file.h
deleted file mode 100644
index ecd096a..0000000
--- a/test/swfedit_file.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef __SWFEDIT_FILE_H__
-#define __SWFEDIT_FILE_H__
-
-#include <libswfdec/swfdec_rect.h>
-#include "swfedit_token.h"
-
-G_BEGIN_DECLS
-
-typedef struct _SwfeditFile SwfeditFile;
-typedef struct _SwfeditFileClass SwfeditFileClass;
-
-#define SWFEDIT_TYPE_FILE                    (swfedit_file_get_type())
-#define SWFEDIT_IS_FILE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_FILE))
-#define SWFEDIT_IS_FILE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_FILE))
-#define SWFEDIT_FILE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_FILE, SwfeditFile))
-#define SWFEDIT_FILE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_FILE, SwfeditFileClass))
-#define SWFEDIT_FILE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_FILE, SwfeditFileClass))
-
-struct _SwfeditFile {
-  SwfeditToken		token;
-
-  char *		filename;	/* name this file is saved to */
-};
-
-struct _SwfeditFileClass {
-  SwfeditTokenClass	token_class;
-};
-
-GType		swfedit_file_get_type		(void);
-
-SwfeditFile *	swfedit_file_new		(const char *	filename,
-						 GError **	error);
-
-gboolean	swfedit_file_save		(SwfeditFile *	file,
-						 GError **	error);
-guint		swfedit_file_get_version	(SwfeditFile *	file);
-
-
-G_END_DECLS
-
-#endif
diff --git a/test/swfedit_list.c b/test/swfedit_list.c
deleted file mode 100644
index 45e0dd5..0000000
--- a/test/swfedit_list.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "swfedit_list.h"
-
-G_DEFINE_TYPE (SwfeditList, swfedit_list, SWFEDIT_TYPE_TOKEN)
-
-static void
-swfedit_list_dispose (GObject *object)
-{
-  //SwfeditList *list = SWFEDIT_LIST (object);
-
-  G_OBJECT_CLASS (swfedit_list_parent_class)->dispose (object);
-}
-
-static void
-swfedit_list_changed (SwfeditToken *token, guint i)
-{
-  guint j;
-  SwfeditList *list = SWFEDIT_LIST (token);
-  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-
-  /* update visibility */
-  for (j = i + 1; j % list->n_defs != 0; j++) {
-    if (list->def[j].n_items == (j % list->n_defs) + 1) {
-      swfedit_token_set_visible (token, j, entry->value != NULL);
-    }
-  }
-  /* update length */
-  j = list->def[i % list->n_defs].n_items;
-  if (j != 0) {
-    entry = &g_array_index (token->tokens, 
-	SwfeditTokenEntry, j - 1);
-    if (entry->type == SWFEDIT_TOKEN_UINT32) {
-      SwfdecOut *out = swfdec_out_open ();
-      SwfdecBuffer *buffer;
-      swfedit_tag_write_token (token, out, i);
-      buffer = swfdec_out_close (out);
-      if (entry->value != GUINT_TO_POINTER (buffer->length)) {
-	swfedit_token_set (token, i / list->n_defs * list->n_defs + j - 1, 
-	    GUINT_TO_POINTER (buffer->length));
-      }
-      swfdec_buffer_unref (buffer);
-    }
-  }
-  /* maybe add items */
-  if (i == token->tokens->len - 1) {
-    for (j = 0; j < list->n_defs; j++) {
-      const SwfeditTagDefinition *def = &list->def[(j + 1) % list->n_defs];
-      swfedit_tag_add_token (SWFEDIT_TOKEN (list), def->name, def->type, def->hint);
-    }
-  }
-}
-
-static void
-swfedit_list_class_init (SwfeditListClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  SwfeditTokenClass *token_class = SWFEDIT_TOKEN_CLASS (klass);
-
-  object_class->dispose = swfedit_list_dispose;
-
-  token_class->changed = swfedit_list_changed;
-}
-
-static void
-swfedit_list_init (SwfeditList *list)
-{
-}
-
-static SwfeditList *
-swfedit_list_new_internal (const SwfeditTagDefinition *def)
-{
-  SwfeditList *list;
-
-  list = g_object_new (SWFEDIT_TYPE_LIST, NULL);
-  list->def = def;
-  for (; def->name; def++)
-    list->n_defs++;
-
-  return list;
-}
-
-SwfeditList *
-swfedit_list_new (const SwfeditTagDefinition *def)
-{
-  SwfeditList *list;
-
-  g_return_val_if_fail (def != NULL, NULL);
-
-  list = swfedit_list_new_internal (def);
-  swfedit_tag_add_token (SWFEDIT_TOKEN (list), def->name, def->type, def->hint);
-
-  return list;
-}
-
-SwfeditList *
-swfedit_list_new_read (SwfeditToken *parent, SwfdecBits *bits, const SwfeditTagDefinition *def)
-{
-  SwfeditList *list;
-  SwfeditTokenEntry *entry;
-  guint offset;
-
-  g_return_val_if_fail (bits != NULL, NULL);
-  g_return_val_if_fail (def != NULL, NULL);
-
-  list = swfedit_list_new_internal (def);
-  SWFEDIT_TOKEN (list)->parent = parent;
-  offset = 0;
-  while (TRUE) {
-    def = list->def;
-    swfedit_tag_read_tag (SWFEDIT_TOKEN (list), bits, def);
-    entry = &g_array_index (SWFEDIT_TOKEN (list)->tokens, SwfeditTokenEntry,
-	SWFEDIT_TOKEN (list)->tokens->len - 1);
-    if (GPOINTER_TO_UINT (entry->value) == 0)
-      break;
-
-    def++;
-    for (;def->name != NULL; def++) {
-      SwfeditTagDefinition def2 = *def;
-      if (def2.n_items)
-	def2.n_items += offset;
-      swfedit_tag_read_tag (SWFEDIT_TOKEN (list), bits, &def2);
-    }
-    offset += list->n_defs;
-  }
-  return list;
-}
-
diff --git a/test/swfedit_list.h b/test/swfedit_list.h
deleted file mode 100644
index e0666f7..0000000
--- a/test/swfedit_list.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef __SWFEDIT_LIST_H__
-#define __SWFEDIT_LIST_H__
-
-#include "swfdec_out.h"
-#include "swfedit_tag.h"
-
-G_BEGIN_DECLS
-
-typedef struct _SwfeditList SwfeditList;
-typedef struct _SwfeditListClass SwfeditListClass;
-
-#define SWFEDIT_TYPE_LIST                    (swfedit_list_get_type())
-#define SWFEDIT_IS_LIST(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_LIST))
-#define SWFEDIT_IS_LIST_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_LIST))
-#define SWFEDIT_LIST(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_LIST, SwfeditList))
-#define SWFEDIT_LIST_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_LIST, SwfeditListClass))
-#define SWFEDIT_LIST_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_LIST, SwfeditListClass))
-
-struct _SwfeditList {
-  SwfeditToken			token;
-
-  const SwfeditTagDefinition *	def;	/* definition of our items */
-  guint				n_defs;	/* number of items in def */
-};
-
-struct _SwfeditListClass {
-  SwfeditTokenClass	token_class;
-};
-
-GType		swfedit_list_get_type	(void);
-
-SwfeditList *	swfedit_list_new	(const SwfeditTagDefinition *	def);
-SwfeditList *	swfedit_list_new_read	(SwfeditToken *			parent,
-					 SwfdecBits *			bits,
-					 const SwfeditTagDefinition *	def);
-
-SwfdecBuffer *	swfedit_list_write	(SwfeditList *			list);
-
-
-G_END_DECLS
-
-#endif
diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c
deleted file mode 100644
index 4a4bf67..0000000
--- a/test/swfedit_tag.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <gtk/gtk.h>
-
-#include <libswfdec/swfdec_bits.h>
-#include <libswfdec/swfdec_debug.h>
-#include <libswfdec/swfdec_script_internal.h>
-#include <libswfdec/swfdec_tag.h>
-#include "swfedit_tag.h"
-#include "swfdec_out.h"
-#include "swfedit_file.h"
-#include "swfedit_list.h"
-
-/*** LOAD/SAVE ***/
-
-static void
-swfedit_object_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  SwfdecBuffer *buffer;
-
-  g_assert (SWFEDIT_IS_TOKEN (data));
-  buffer = swfedit_tag_write (data);
-  swfdec_out_put_buffer (out, buffer);
-  swfdec_buffer_unref (buffer);
-}
-
-static gpointer
-swfedit_object_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return swfedit_list_new_read (token, bits, hint);
-}
-
-static void
-swfedit_binary_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_buffer (out, data);
-}
-
-static gpointer
-swfedit_binary_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, -1);
-  if (buffer == NULL)
-    buffer = swfdec_buffer_new ();
-  return buffer;
-}
-
-static void
-swfedit_bit_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_bit (out, data ? TRUE : FALSE);
-}
-
-static gpointer
-swfedit_bit_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return GUINT_TO_POINTER (swfdec_bits_getbit (bits) ? 1 : 0);
-}
-
-static void
-swfedit_u8_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_u8 (out, GPOINTER_TO_UINT (data));
-}
-
-static gpointer
-swfedit_u8_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return GUINT_TO_POINTER ((gulong) swfdec_bits_get_u8 (bits));
-}
-
-static void
-swfedit_u16_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_u16 (out, GPOINTER_TO_UINT (data));
-}
-
-static gpointer
-swfedit_u16_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits));
-}
-
-static void
-swfedit_u32_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_u32 (out, GPOINTER_TO_UINT (data));
-}
-
-static gpointer
-swfedit_u32_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits));
-}
-
-static void
-swfedit_rect_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_rect (out, data);
-}
-
-static gpointer
-swfedit_rect_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  SwfdecRect *rect = g_new (SwfdecRect, 1);
-  swfdec_bits_get_rect (bits, rect);
-  swfdec_bits_syncbits (bits);
-  return rect;
-}
-
-static void
-swfedit_string_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_string (out, data);
-}
-
-static gpointer
-swfedit_string_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  char *s;
-  s = swfdec_bits_get_string (bits, 7);
-  if (s == NULL)
-    s = g_strdup ("");
-  return s;
-}
-
-static void
-swfedit_rgb_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_rgb (out, GPOINTER_TO_UINT (data));
-}
-
-static gpointer
-swfedit_rgb_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return GUINT_TO_POINTER (swfdec_bits_get_color (bits));
-}
-
-static void
-swfedit_rgba_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_rgba (out, GPOINTER_TO_UINT (data));
-}
-
-static gpointer
-swfedit_rgba_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  return GUINT_TO_POINTER (swfdec_bits_get_rgba (bits));
-}
-
-static void
-swfedit_matrix_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_matrix (out, data);
-}
-
-static gpointer
-swfedit_matrix_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  cairo_matrix_t *matrix = g_new (cairo_matrix_t, 1);
-
-  swfdec_bits_get_matrix (bits, matrix, NULL);
-  swfdec_bits_syncbits (bits);
-  return matrix;
-}
-
-static void
-swfedit_ctrans_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  swfdec_out_put_color_transform (out, data);
-}
-
-static gpointer
-swfedit_ctrans_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  SwfdecColorTransform *ctrans = g_new (SwfdecColorTransform, 1);
-
-  swfdec_bits_get_color_transform (bits, ctrans);
-  swfdec_bits_syncbits (bits);
-  return ctrans;
-}
-
-static void
-swfedit_script_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  SwfdecScript *script = data;
-
-  swfdec_out_put_buffer (out, script->buffer);
-}
-
-static gpointer
-swfedit_script_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  while (token->parent)
-    token = token->parent;
-  if (!SWFEDIT_IS_FILE (token))
-    return NULL;
-  return swfdec_script_new_from_bits (bits, "original script", swfedit_file_get_version (SWFEDIT_FILE (token)));
-}
-
-static void
-swfedit_clipeventflags_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
-{
-  while (token->parent)
-    token = token->parent;
-  g_assert (SWFEDIT_IS_FILE (token));
-  if (swfedit_file_get_version (SWFEDIT_FILE (token)) >= 6)
-    swfdec_out_put_u32 (out, GPOINTER_TO_UINT (data));
-  else
-    swfdec_out_put_u16 (out, GPOINTER_TO_UINT (data));
-}
-
-static gpointer
-swfedit_clipeventflags_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
-{
-  while (token->parent)
-    token = token->parent;
-  g_assert (SWFEDIT_IS_FILE (token));
-  if (swfedit_file_get_version (SWFEDIT_FILE (token)) >= 6)
-    return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits));
-  else
-    return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits));
-}
-
-struct {
-  void		(* write)	(SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint);
-  gpointer	(* read)	(SwfeditToken *token, SwfdecBits *bits, gconstpointer hint);
-} operations[SWFEDIT_N_TOKENS] = {
-  { swfedit_object_write, swfedit_object_read },
-  { swfedit_binary_write, swfedit_binary_read },
-  { swfedit_bit_write, swfedit_bit_read },
-  { swfedit_u8_write, swfedit_u8_read },
-  { swfedit_u16_write, swfedit_u16_read },
-  { swfedit_u32_write, swfedit_u32_read },
-  { swfedit_string_write, swfedit_string_read },
-  { swfedit_rect_write, swfedit_rect_read },
-  { swfedit_rgb_write, swfedit_rgb_read },
-  { swfedit_rgba_write, swfedit_rgba_read },
-  { swfedit_matrix_write, swfedit_matrix_read },
-  { swfedit_ctrans_write, swfedit_ctrans_read },
-  { swfedit_script_write, swfedit_script_read },
-  { swfedit_clipeventflags_write, swfedit_clipeventflags_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 (token, entry->value, out, NULL);
-}
-
-SwfdecBuffer *
-swfedit_tag_write (SwfeditToken *token)
-{
-  guint i;
-  SwfdecOut *out;
-
-  g_return_val_if_fail (SWFEDIT_IS_TOKEN (token), NULL);
-
-  out = swfdec_out_open ();
-  for (i = 0; i < token->tokens->len; i++) {
-    SwfeditTokenEntry *entry = &g_array_index (token->tokens, 
-	SwfeditTokenEntry, i);
-    if (entry->visible)
-      swfedit_tag_write_token (token, out, i);
-  }
-  return swfdec_out_close (out);
-}
-
-void
-swfedit_tag_read_token (SwfeditToken *token, SwfdecBits *bits,
-    const char *name, SwfeditTokenType type, gconstpointer hint)
-{
-  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 (token, bits, hint);
-  swfedit_token_add (token, name, type, data);
-}
-
-/*** TAGS ***/
-
-static const SwfeditTagDefinition ShowFrame[] = { { NULL, 0, 0, NULL } };
-static const SwfeditTagDefinition SetBackgroundColor[] = { { "color", SWFEDIT_TOKEN_RGB, 0, NULL }, { NULL, 0, 0, NULL } };
-static const SwfeditTagDefinition PlaceObject2Action[] = {
-  { "flags", SWFEDIT_TOKEN_CLIPEVENTFLAGS, 0, NULL },
-  { "size", SWFEDIT_TOKEN_UINT32, 0, NULL },
-  //{ "key code", SWFEDIT_TOKEN_UINT8, 0, NULL }, /* only if flag foo is set */
-  { "script", SWFEDIT_TOKEN_SCRIPT, 2, NULL },
-  { NULL, 0, 0, NULL }
-};
-static const SwfeditTagDefinition PlaceObject2[] = { 
-  { "has clip actions", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "has clip depth", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "has name", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "has ratio", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "has color transform", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "has matrix", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "has character", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "move", SWFEDIT_TOKEN_BIT, 0, NULL }, 
-  { "depth", SWFEDIT_TOKEN_UINT16, 0, NULL }, 
-  { "character", SWFEDIT_TOKEN_UINT16, 7, NULL }, 
-  { "matrix", SWFEDIT_TOKEN_MATRIX, 6, NULL }, 
-  { "color transform", SWFEDIT_TOKEN_CTRANS, 5, NULL }, 
-  { "ratio", SWFEDIT_TOKEN_UINT16, 4, NULL }, 
-  { "name", SWFEDIT_TOKEN_STRING, 3, NULL }, 
-  { "clip depth", SWFEDIT_TOKEN_UINT16, 2, NULL }, 
-  { "reserved", SWFEDIT_TOKEN_UINT16, 1, NULL },
-  { "all flags", SWFEDIT_TOKEN_CLIPEVENTFLAGS, 1, NULL },
-  { "actions", SWFEDIT_TOKEN_OBJECT, 1, PlaceObject2Action },
-  { NULL, 0, 0, NULL }
-};
-static const SwfeditTagDefinition DoAction[] = {
-  { "action", SWFEDIT_TOKEN_SCRIPT, 0, NULL },
-  { NULL, 0, 0, NULL }
-};
-static const SwfeditTagDefinition DoInitAction[] = {
-  { "character", SWFEDIT_TOKEN_UINT16, 0, NULL },
-  { "action", SWFEDIT_TOKEN_SCRIPT, 0, NULL },
-  { NULL, 0, 0, NULL }
-};
-
-static const SwfeditTagDefinition *tags[] = {
-  [SWFDEC_TAG_SHOWFRAME] = ShowFrame,
-  [SWFDEC_TAG_SETBACKGROUNDCOLOR] = SetBackgroundColor,
-  [SWFDEC_TAG_PLACEOBJECT2] = PlaceObject2,
-  [SWFDEC_TAG_DOACTION] = DoAction,
-  [SWFDEC_TAG_DOINITACTION] = DoInitAction,
-};
-
-static const SwfeditTagDefinition *
-swfedit_tag_get_definition (guint tag)
-{
-  if (tag >= G_N_ELEMENTS (tags))
-    return NULL;
-  return tags[tag];
-}
-
-/*** SWFEDIT_TAG ***/
-
-G_DEFINE_TYPE (SwfeditTag, swfedit_tag, SWFEDIT_TYPE_TOKEN)
-
-static void
-swfedit_tag_dispose (GObject *object)
-{
-  //SwfeditTag *tag = SWFEDIT_TAG (object);
-
-  G_OBJECT_CLASS (swfedit_tag_parent_class)->dispose (object);
-}
-
-static void
-swfedit_tag_changed (SwfeditToken *token, guint i)
-{
-  guint j;
-  SwfeditTag *tag = SWFEDIT_TAG (token);
-  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-  const SwfeditTagDefinition *def = swfedit_tag_get_definition (tag->tag);
-
-  if (def == NULL)
-    return;
-
-  for (j = i + 1; def[j].name; j++) {
-    if (def[j].n_items == i + 1) {
-      swfedit_token_set_visible (token, j, entry->value != NULL);
-    }
-  }
-  if (def[i].n_items != 0) {
-    entry = &g_array_index (token->tokens, 
-	SwfeditTokenEntry, def[i].n_items - 1);
-    if (entry->type == SWFEDIT_TOKEN_UINT32) {
-      SwfdecOut *out = swfdec_out_open ();
-      SwfdecBuffer *buffer;
-      swfedit_tag_write_token (token, out, def[i].n_items - 1);
-      buffer = swfdec_out_close (out);
-      if (entry->value != GUINT_TO_POINTER (buffer->length)) {
-	swfedit_token_set (token, def[i].n_items - 1, 
-	    GUINT_TO_POINTER (buffer->length));
-      }
-      swfdec_buffer_unref (buffer);
-    }
-  }
-}
-
-static void
-swfedit_tag_class_init (SwfeditTagClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  SwfeditTokenClass *token_class = SWFEDIT_TOKEN_CLASS (klass);
-
-  object_class->dispose = swfedit_tag_dispose;
-
-  token_class->changed = swfedit_tag_changed;
-}
-
-static void
-swfedit_tag_init (SwfeditTag *tag)
-{
-}
-
-void
-swfedit_tag_add_token (SwfeditToken *token, const char *name, SwfeditTokenType type,
-    gconstpointer hint)
-{
-  gpointer data;
-
-  if (type == SWFEDIT_TOKEN_OBJECT) {
-    data = swfedit_list_new (hint);
-    SWFEDIT_TOKEN (data)->parent = token;
-  } else {
-    data = swfedit_token_new_token (type);
-  }
-  swfedit_token_add (token, name, type, data);
-}
-
-void
-swfedit_tag_read_tag (SwfeditToken *token, SwfdecBits *bits, 
-    const SwfeditTagDefinition *def)
-{
-  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
-  g_return_if_fail (bits != NULL);
-  g_return_if_fail (def != NULL);
-
-  if (def->n_items != 0) {
-    SwfeditTokenEntry *entry = &g_array_index (token->tokens, 
-	SwfeditTokenEntry, def->n_items - 1);
-    if (GPOINTER_TO_UINT (entry->value) == 0) {
-      swfedit_tag_add_token (token, def->name, def->type, def->hint);
-      swfedit_token_set_visible (token, token->tokens->len - 1, FALSE);
-    } else if (entry->type == SWFEDIT_TOKEN_BIT) {
-      swfedit_tag_read_token (token, bits, def->name, def->type, def->hint);
-    } else {
-      guint length = GPOINTER_TO_UINT (entry->value);
-      SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, length);
-      if (buffer == NULL) {
-	swfedit_tag_add_token (token, def->name, def->type, def->hint);
-      } else {
-	SwfdecBits bits2;
-	swfdec_bits_init (&bits2, buffer);
-	swfedit_tag_read_token (token, &bits2, def->name, def->type, def->hint);
-	swfdec_buffer_unref (buffer);
-      }
-    }
-  } else {
-    swfedit_tag_read_token (token, bits, def->name, def->type, def->hint);
-  }
-}
-
-SwfeditTag *
-swfedit_tag_new (SwfeditToken *parent, guint tag, SwfdecBuffer *buffer)
-{
-  SwfeditTag *item;
-  const SwfeditTagDefinition *def;
-
-  g_return_val_if_fail (SWFEDIT_IS_TOKEN (parent), NULL);
-
-  item = g_object_new (SWFEDIT_TYPE_TAG, NULL);
-  item->tag = tag;
-  SWFEDIT_TOKEN (item)->parent = parent;
-  def = swfedit_tag_get_definition (tag);
-  if (def) {
-    SwfdecBits bits;
-    swfdec_bits_init (&bits, buffer);
-    for (;def->name != NULL; def++) {
-      swfedit_tag_read_tag (SWFEDIT_TOKEN (item), &bits, def);
-    }
-    if (swfdec_bits_left (&bits)) {
-      SWFDEC_WARNING ("%u bytes %u bits left unparsed", 
-	  swfdec_bits_left (&bits) / 8, swfdec_bits_left (&bits) % 8);
-    }
-  } else {
-    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
deleted file mode 100644
index 2f1d231..0000000
--- a/test/swfedit_tag.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef __SWFEDIT_TAG_H__
-#define __SWFEDIT_TAG_H__
-
-#include <libswfdec/swfdec_buffer.h>
-#include <libswfdec/swfdec_bits.h>
-#include "swfdec_out.h"
-#include "swfedit_token.h"
-
-G_BEGIN_DECLS
-
-typedef struct _SwfeditTag SwfeditTag;
-typedef struct _SwfeditTagClass SwfeditTagClass;
-typedef struct _SwfeditTagDefinition SwfeditTagDefinition;
-
-struct _SwfeditTagDefinition {
-  const char *	  	name;			/* name to use for this field */
-  SwfeditTokenType     	type;			/* type of this field */
-  guint			n_items;		/* 1-indexed field to look at for item count (or 0 to use 1 item) */
-  gconstpointer		hint;			/* hint to pass to field when creating */
-};
-
-#define SWFEDIT_TYPE_TAG                    (swfedit_tag_get_type())
-#define SWFEDIT_IS_TAG(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TAG))
-#define SWFEDIT_IS_TAG_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TAG))
-#define SWFEDIT_TAG(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TAG, SwfeditTag))
-#define SWFEDIT_TAG_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TAG, SwfeditTagClass))
-#define SWFEDIT_TAG_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TAG, SwfeditTagClass))
-
-struct _SwfeditTag {
-  SwfeditToken		token;
-
-  guint			tag;		/* tag type */
-};
-
-struct _SwfeditTagClass {
-  SwfeditTokenClass	token_class;
-};
-
-GType		swfedit_tag_get_type	(void);
-
-SwfeditTag *	swfedit_tag_new		(SwfeditToken *		parent,
-					 guint			tag,
-					 SwfdecBuffer *		buffer);
-
-SwfdecBuffer *	swfedit_tag_write	(SwfeditToken *		token);
-void		swfedit_tag_write_token	(SwfeditToken *		token,
-					 SwfdecOut *		out,
-					 guint			i);
-void		swfedit_tag_add_token	(SwfeditToken *		token,
-					 const char *		name,
-					 SwfeditTokenType	type,
-					 gconstpointer		hint);
-void		swfedit_tag_read_token	(SwfeditToken *		token, 
-					 SwfdecBits *		bits,
-					 const char *		name,
-					 SwfeditTokenType	type,
-					 gconstpointer		hint);
-void		swfedit_tag_read_tag	(SwfeditToken *		token,
-					 SwfdecBits *		bits, 
-					 const SwfeditTagDefinition *def);
-
-G_END_DECLS
-
-#endif
diff --git a/test/swfedit_token.c b/test/swfedit_token.c
deleted file mode 100644
index 34496df..0000000
--- a/test/swfedit_token.c
+++ /dev/null
@@ -1,797 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, to_string to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include <libswfdec/swfdec_buffer.h>
-#include <libswfdec/swfdec_color.h>
-#include <libswfdec/swfdec_script_internal.h>
-#include "swfedit_token.h"
-
-/*** CONVERTERS ***/
-
-static gboolean
-swfedit_parse_hex (const char *s, guint *result)
-{
-  guint byte;
-
-  if (s[0] >= '0' && s[0] <= '9')
-    byte = s[0] - '0';
-  else if (s[0] >= 'a' && s[0] <= 'f')
-    byte = s[0] + 10 - 'a';
-  else if (s[0] >= 'A' && s[0] <= 'F')
-    byte = s[0] + 10 - 'A';
-  else
-    return FALSE;
-  s++;
-  byte *= 16;
-  if (s[0] >= '0' && s[0] <= '9')
-    byte += s[0] - '0';
-  else if (s[0] >= 'a' && s[0] <= 'f')
-    byte += s[0] + 10 - 'a';
-  else if (s[0] >= 'A' && s[0] <= 'F')
-    byte += s[0] + 10 - 'A';
-  else
-    return FALSE;
-  *result = byte;
-  return TRUE;
-}
-
-static gpointer
-swfedit_binary_new (void)
-{
-  return swfdec_buffer_new ();
-}
-
-static gboolean
-swfedit_binary_from_string (const char *s, gpointer* result)
-{
-  GByteArray *array = g_byte_array_new ();
-  guint byte;
-  guint8 add;
-
-  while (g_ascii_isspace (*s)) s++;
-  do {
-    if (!swfedit_parse_hex (s, &byte))
-      break;
-    s += 2;
-    add = byte;
-    g_byte_array_append (array, &add, 1);
-    while (g_ascii_isspace (*s)) s++;
-  } while (*s != '\0');
-  if (*s == '\0') {
-    SwfdecBuffer *buffer = swfdec_buffer_new ();
-    buffer->length = array->len;
-    buffer->data = array->data;
-    g_byte_array_free (array, FALSE);
-    *result = buffer;
-    return TRUE;
-  }
-  g_byte_array_free (array, TRUE);
-  return FALSE;
-}
-
-static char *
-swfedit_binary_to_string (gconstpointer value)
-{
-  guint i;
-  const SwfdecBuffer *buffer = value;
-  GString *string = g_string_new ("");
-
-  for (i = 0; i < buffer->length; i++) {
-    if (i && i % 4 == 0)
-      g_string_append_c (string, ' ');
-    g_string_append_printf (string, "%02X", buffer->data[i]);
-  }
-  return g_string_free (string, FALSE);
-}
-
-static gboolean
-swfedit_bit_from_string (const char *s, gpointer* result)
-{
-  if (s[0] == '1' && s[1] == '\0')
-    *result = GUINT_TO_POINTER (1);
-  else if (s[0] == '0' && s[1] == '\0')
-    *result = GUINT_TO_POINTER (0);
-  else
-    return FALSE;
-  return TRUE;
-}
-
-static char *
-swfedit_bit_to_string (gconstpointer value)
-{
-  return g_strdup (value ? "1" : "0");
-}
-
-static gboolean
-swfedit_from_string_unsigned (const char *s, gulong max, gpointer* result)
-{
-  char *end;
-  gulong u;
-
-  g_assert (max <= G_MAXUINT);
-  u = strtoul (s, &end, 10);
-  if (*end != '\0')
-    return FALSE;
-  if (u > max)
-    return FALSE;
-  *result = GUINT_TO_POINTER (u);
-  return TRUE;
-}
-
-static gboolean
-swfedit_uint8_from_string (const char *s, gpointer* result)
-{
-  return swfedit_from_string_unsigned (s, G_MAXUINT8, result);
-}
-
-static gboolean
-swfedit_uint16_from_string (const char *s, gpointer* result)
-{
-  return swfedit_from_string_unsigned (s, G_MAXUINT16, result);
-}
-
-static gboolean
-swfedit_uint32_from_string (const char *s, gpointer* result)
-{
-  return swfedit_from_string_unsigned (s, G_MAXUINT32, result);
-}
-
-static char *
-swfedit_to_string_unsigned (gconstpointer value)
-{
-  return g_strdup_printf ("%u", GPOINTER_TO_UINT (value));
-}
-
-static char *
-swfedit_string_to_string (gconstpointer value)
-{
-  return g_strdup (value);
-}
-
-static gboolean
-swfedit_string_from_string (const char *s, gpointer* result)
-{
-  *result = g_strdup (s);
-  return TRUE;
-}
-
-static gpointer
-swfedit_rect_new (void)
-{
-  return g_new0 (SwfdecRect, 1);
-}
-
-static gboolean
-swfedit_rect_from_string (const char *s, gpointer* result)
-{
-  return FALSE;
-}
-
-static char *
-swfedit_rect_to_string (gconstpointer value)
-{
-  const SwfdecRect *rect = value;
-
-  return g_strdup_printf ("%d, %d, %d, %d", (int) rect->x0, (int) rect->y0,
-      (int) rect->x1, (int) rect->y1);
-}
-
-static gboolean
-swfedit_rgb_from_string (const char *s, gpointer* result)
-{
-  guint r, g, b;
-  if (strlen (s) != 6)
-    return FALSE;
-  if (!swfedit_parse_hex (s, &r))
-    return FALSE;
-  s += 2;
-  if (!swfedit_parse_hex (s, &g))
-    return FALSE;
-  s += 2;
-  if (!swfedit_parse_hex (s, &b))
-    return FALSE;
-  *result = GUINT_TO_POINTER (SWFDEC_COLOR_COMBINE (r, g, b, 0xFF));
-  return TRUE;
-}
-
-static char *
-swfedit_rgb_to_string (gconstpointer value)
-{
-  guint c = GPOINTER_TO_UINT (value);
-
-  return g_strdup_printf ("%02X%02X%02X", SWFDEC_COLOR_R (c),
-      SWFDEC_COLOR_G (c), SWFDEC_COLOR_B (c));
-}
-
-static gboolean
-swfedit_rgba_from_string (const char *s, gpointer* result)
-{
-  guint r, g, b, a;
-  if (strlen (s) != 8)
-    return FALSE;
-  if (!swfedit_parse_hex (s, &a))
-    return FALSE;
-  s += 2;
-  if (!swfedit_parse_hex (s, &r))
-    return FALSE;
-  s += 2;
-  if (!swfedit_parse_hex (s, &g))
-    return FALSE;
-  s += 2;
-  if (!swfedit_parse_hex (s, &b))
-    return FALSE;
-  *result = GUINT_TO_POINTER (SWFDEC_COLOR_COMBINE (r, g, b, a));
-  return TRUE;
-}
-
-static char *
-swfedit_rgba_to_string (gconstpointer value)
-{
-  guint c = GPOINTER_TO_UINT (value);
-
-  return g_strdup_printf ("%02X%02X%02X%02X", SWFDEC_COLOR_R (c),
-      SWFDEC_COLOR_G (c), SWFDEC_COLOR_B (c), SWFDEC_COLOR_A (c));
-}
-
-static gpointer
-swfedit_matrix_new (void)
-{
-  cairo_matrix_t *matrix = g_new (cairo_matrix_t, 1);
-
-  cairo_matrix_init_identity (matrix);
-  return matrix;
-}
-
-static gboolean
-swfedit_matrix_from_string (const char *s, gpointer* result)
-{
-  return FALSE;
-}
-
-static char *
-swfedit_matrix_to_string (gconstpointer value)
-{
-  const cairo_matrix_t *mat = value;
-
-  return g_strdup_printf ("{%g %g,  %g %g} + {%g, %g}", 
-      mat->xx, mat->xy, mat->yx, mat->yy, mat->x0, mat->y0);
-}
-
-static gpointer
-swfedit_ctrans_new (void)
-{
-  SwfdecColorTransform *trans = g_new (SwfdecColorTransform, 1);
-
-  swfdec_color_transform_init_identity (trans);
-  return trans;
-}
-
-static gboolean
-swfedit_ctrans_from_string (const char *s, gpointer* result)
-{
-  return FALSE;
-}
-
-static char *
-swfedit_ctrans_to_string (gconstpointer value)
-{
-  const SwfdecColorTransform *trans = value;
-
-  return g_strdup_printf ("{%d %d} {%d %d} {%d %d} {%d %d}", 
-      trans->ra, trans->rb, trans->ga, trans->gb, 
-      trans->ba, trans->bb, trans->aa, trans->ab);
-}
-
-static gpointer
-swfedit_script_new (void)
-{
-  return NULL;
-}
-
-static gboolean
-swfedit_script_from_string (const char *s, gpointer* result)
-{
-  gpointer buffer;
-  SwfdecScript *script;
-  
-  if (!swfedit_binary_from_string (s, &buffer)) {
-    return FALSE;
-  }
-
-  script = swfdec_script_new (buffer, "unknown", 6 /* FIXME */);
-  if (script != NULL) {
-    *result = script;
-    return TRUE;
-  } else {
-    return FALSE;
-  }
-}
-
-static char *
-swfedit_script_to_string (gconstpointer value)
-{
-  if (value == NULL)
-    return g_strdup ("");
-  else
-    return swfedit_binary_to_string (((SwfdecScript *) value)->buffer);
-}
-
-static void
-swfedit_script_free (gpointer script)
-{
-  if (script)
-    swfdec_script_unref (script);
-}
-
-struct {
-  gpointer	(* new)		(void);
-  gboolean	(* from_string)	(const char *s, gpointer *);
-  char *	(* to_string)	(gconstpointer value);
-  void	  	(* free)	(gpointer value);
-} converters[SWFEDIT_N_TOKENS] = {
-  { NULL, NULL, NULL, g_object_unref },
-  { swfedit_binary_new, swfedit_binary_from_string, swfedit_binary_to_string, (GDestroyNotify) swfdec_buffer_unref },
-  { NULL, swfedit_bit_from_string, swfedit_bit_to_string, NULL },
-  { NULL, swfedit_uint8_from_string, swfedit_to_string_unsigned, NULL },
-  { NULL, swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL },
-  { NULL, swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL },
-  { NULL, swfedit_string_from_string, swfedit_string_to_string, g_free },
-  { swfedit_rect_new, swfedit_rect_from_string, swfedit_rect_to_string, g_free },
-  { NULL, swfedit_rgb_from_string, swfedit_rgb_to_string, NULL },
-  { NULL, swfedit_rgba_from_string, swfedit_rgba_to_string, NULL },
-  { swfedit_matrix_new, swfedit_matrix_from_string, swfedit_matrix_to_string, g_free },
-  { swfedit_ctrans_new, swfedit_ctrans_from_string, swfedit_ctrans_to_string, g_free },
-  { swfedit_script_new, swfedit_script_from_string, swfedit_script_to_string, swfedit_script_free },
-  { NULL, swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL },
-};
-
-gpointer
-swfedit_token_new_token (SwfeditTokenType type)
-{
-  gpointer ret;
-
-  g_assert (type < G_N_ELEMENTS (converters));
-
-  if (!converters[type].new)
-    return NULL;
-  ret = converters[type].new ();
-  return ret;
-}
-
-/*** GTK_TREE_MODEL ***/
-
-#if 0
-#  define REPORT g_print ("%s\n", G_STRFUNC)
-#else
-#  define REPORT 
-#endif
-static GtkTreeModelFlags 
-swfedit_token_get_flags (GtkTreeModel *tree_model)
-{
-  REPORT;
-  return 0;
-}
-
-static gint
-swfedit_token_get_n_columns (GtkTreeModel *tree_model)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (tree_model);
-
-  REPORT;
-  return token->tokens->len;
-}
-
-static GType
-swfedit_token_get_column_type (GtkTreeModel *tree_model, gint index_)
-{
-  REPORT;
-  switch (index_) {
-    case SWFEDIT_COLUMN_NAME:
-      return G_TYPE_STRING;
-    case SWFEDIT_COLUMN_VALUE_VISIBLE:
-      return G_TYPE_BOOLEAN;
-    case SWFEDIT_COLUMN_VALUE_EDITABLE:
-      return G_TYPE_BOOLEAN;
-    case SWFEDIT_COLUMN_VALUE:
-      return G_TYPE_STRING;
-    default:
-      break;
-  }
-  g_assert_not_reached ();
-  return G_TYPE_NONE;
-}
-
-static gboolean
-swfedit_token_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (tree_model);
-  guint i = gtk_tree_path_get_indices (path)[0];
-  SwfeditTokenEntry *entry;
-  
-  REPORT;
-  if (i > token->tokens->len)
-    return FALSE;
-  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-  if (gtk_tree_path_get_depth (path) > 1) {
-    GtkTreePath *new;
-    int j;
-    int *indices;
-    gboolean ret;
-
-    if (entry->type != SWFEDIT_TOKEN_OBJECT)
-      return FALSE;
-    new = gtk_tree_path_new ();
-    indices = gtk_tree_path_get_indices (path);
-    for (j = 1; j < gtk_tree_path_get_depth (path); j++) {
-      gtk_tree_path_append_index (new, indices[j]);
-    }
-    ret = swfedit_token_get_iter (GTK_TREE_MODEL (entry->value), iter, new);
-    gtk_tree_path_free (new);
-    return ret;
-  } else {
-    iter->stamp = 0; /* FIXME */
-    iter->user_data = token;
-    iter->user_data2 = GINT_TO_POINTER (i);
-    return TRUE;
-  }
-}
-
-static GtkTreePath *
-swfedit_token_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
-  GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data2), -1);
-
-  REPORT;
-  while (token->parent) {
-    guint i;
-    SwfeditToken *parent = token->parent;
-    for (i = 0; i < parent->tokens->len; i++) {
-      SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i);
-      if (entry->type != SWFEDIT_TOKEN_OBJECT)
-	continue;
-      if (entry->value == token)
-	break;
-    }
-    gtk_tree_path_prepend_index (path, i);
-    token = parent;
-  }
-  return path;
-}
-
-static void 
-swfedit_token_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter,
-    gint column, GValue *value)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
-  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2));
-
-  REPORT;
-  switch (column) {
-    case SWFEDIT_COLUMN_NAME:
-      g_value_init (value, G_TYPE_STRING);
-      g_value_set_string (value, entry->name);
-      return;
-    case SWFEDIT_COLUMN_VALUE_VISIBLE:
-      g_value_init (value, G_TYPE_BOOLEAN);
-      g_value_set_boolean (value, converters[entry->type].to_string != NULL);
-      return;
-    case SWFEDIT_COLUMN_VALUE_EDITABLE:
-      g_value_init (value, G_TYPE_BOOLEAN);
-      g_value_set_boolean (value, entry->visible);
-      return;
-    case SWFEDIT_COLUMN_VALUE:
-      g_value_init (value, G_TYPE_STRING);
-      if (converters[entry->type].to_string)
-	g_value_take_string (value, converters[entry->type].to_string (entry->value));
-      return;
-    default:
-      break;
-  }
-  g_assert_not_reached ();
-}
-
-static gboolean
-swfedit_token_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
-  int i;
-
-  REPORT;
-  i = GPOINTER_TO_INT (iter->user_data2) + 1;
-  if ((guint) i >= token->tokens->len)
-    return FALSE;
-
-  iter->user_data2 = GINT_TO_POINTER (i);
-  return TRUE;
-}
-
-static gboolean
-swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
-{
-  SwfeditToken *token;
-  SwfeditTokenEntry *entry;
-
-  REPORT;
-  if (parent) {
-    token = SWFEDIT_TOKEN (parent->user_data);
-    entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2));
-    if (entry->type != SWFEDIT_TOKEN_OBJECT)
-      return FALSE;
-    token = entry->value;
-  } else {
-    token = SWFEDIT_TOKEN (tree_model);
-  }
-  if (token->tokens->len == 0)
-    return FALSE;
-  iter->stamp = 0; /* FIXME */
-  iter->user_data = token;
-  iter->user_data2 = GINT_TO_POINTER (0);
-  return TRUE;
-}
-
-static gboolean
-swfedit_token_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
-  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2));
-
-  REPORT;
-  return entry->type == SWFEDIT_TOKEN_OBJECT && SWFEDIT_TOKEN (entry->value)->tokens->len > 0;
-}
-
-static gint
-swfedit_token_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
-  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2));
-
-  REPORT;
-  if (entry->type != SWFEDIT_TOKEN_OBJECT)
-    return 0;
-
-  token = entry->value;
-  return token->tokens->len;
-}
-
-static gboolean
-swfedit_token_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter,
-    GtkTreeIter *parent, gint n)
-{
-  SwfeditToken *token;
-  SwfeditTokenEntry *entry;
-
-  REPORT;
-  if (parent) {
-    token = SWFEDIT_TOKEN (parent->user_data);
-    entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2));
-
-    if (entry->type != SWFEDIT_TOKEN_OBJECT)
-      return FALSE;
-
-    token = entry->value;
-  } else {
-    token = SWFEDIT_TOKEN (tree_model);
-  }
-  if ((guint) n >= token->tokens->len)
-    return FALSE;
-  iter->stamp = 0; /* FIXME */
-  iter->user_data = token;
-  iter->user_data2 = GINT_TO_POINTER (n);
-  return TRUE;
-}
-
-static gboolean
-swfedit_token_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
-{
-  guint i;
-  SwfeditToken *token = SWFEDIT_TOKEN (child->user_data);
-  SwfeditToken *parent = token->parent;
-
-  REPORT;
-  if (parent == NULL)
-    return FALSE;
-
-  for (i = 0; i < parent->tokens->len; i++) {
-    SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i);
-    if (entry->type != SWFEDIT_TOKEN_OBJECT)
-      continue;
-    if (entry->value == token)
-      break;
-  }
-  iter->stamp = 0; /* FIXME */
-  iter->user_data = parent;
-  iter->user_data2 = GINT_TO_POINTER (i);
-  return TRUE;
-}
-
-static void
-swfedit_token_tree_model_init (GtkTreeModelIface *iface)
-{
-  iface->get_flags = swfedit_token_get_flags;
-  iface->get_n_columns = swfedit_token_get_n_columns;
-  iface->get_column_type = swfedit_token_get_column_type;
-  iface->get_iter = swfedit_token_get_iter;
-  iface->get_path = swfedit_token_get_path;
-  iface->get_value = swfedit_token_get_value;
-  iface->iter_next = swfedit_token_iter_next;
-  iface->iter_children = swfedit_token_iter_children;
-  iface->iter_has_child = swfedit_token_iter_has_child;
-  iface->iter_n_children = swfedit_token_iter_n_children;
-  iface->iter_nth_child = swfedit_token_iter_nth_child;
-  iface->iter_parent = swfedit_token_iter_parent;
-}
-
-/*** SWFEDIT_TOKEN ***/
-
-G_DEFINE_TYPE_WITH_CODE (SwfeditToken, swfedit_token, G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, swfedit_token_tree_model_init))
-
-static void
-swfedit_token_dispose (GObject *object)
-{
-  SwfeditToken *token = SWFEDIT_TOKEN (object);
-  guint i;
-
-  for (i = 0; i < token->tokens->len; i++) {
-    SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-    g_free (entry->name);
-    if (converters[entry->type].free)
-      converters[entry->type].free (entry->value);
-  }
-  g_array_free (token->tokens, TRUE);
-
-  G_OBJECT_CLASS (swfedit_token_parent_class)->dispose (object);
-}
-
-static void
-swfedit_token_class_init (SwfeditTokenClass *class)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-  object_class->dispose = swfedit_token_dispose;
-}
-
-static void
-swfedit_token_init (SwfeditToken *token)
-{
-  token->tokens = g_array_new (FALSE, FALSE, sizeof (SwfeditTokenEntry));
-}
-
-SwfeditToken *
-swfedit_token_new (void)
-{
-  SwfeditToken *token;
-
-  token = g_object_new (SWFEDIT_TYPE_TOKEN, NULL);
-  return token;
-}
-
-void
-swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, 
-    gpointer value)
-{
-  SwfeditTokenEntry entry = { NULL, type, value, TRUE };
-
-  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
-  g_return_if_fail (name != NULL);
-  g_return_if_fail (type < SWFEDIT_N_TOKENS);
-
-  g_assert (type != SWFEDIT_TOKEN_OBJECT || value != NULL);
-  entry.name = g_strdup (name);
-  g_array_append_val (token->tokens, entry);
-}
-
-void
-swfedit_token_set (SwfeditToken *token, guint i, gpointer value)
-{
-  SwfeditTokenClass *klass;
-  SwfeditTokenEntry *entry;
-  GtkTreePath *path;
-  SwfeditToken *model;
-  GtkTreeIter iter;
-
-  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
-  g_return_if_fail (i < token->tokens->len);
-
-  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-  if (converters[entry->type].free != NULL)
-    converters[entry->type].free (entry->value);
-  entry->value = value;
-  klass = SWFEDIT_TOKEN_GET_CLASS (token);
-  if (klass->changed)
-    klass->changed (token, i);
-
-  model = token;
-  while (model->parent)
-    model = model->parent;
-  iter.user_data = token;
-  iter.user_data2 = GUINT_TO_POINTER (i);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
-  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
-  gtk_tree_path_free (path);
-}
-
-void
-swfedit_token_set_iter (SwfeditToken *token, GtkTreeIter *iter, const char *value)
-{
-  SwfeditTokenClass *klass;
-  GtkTreeModel *model;
-  SwfeditTokenEntry *entry;
-  guint i;
-  gpointer new;
-  GtkTreePath *path;
-
-  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
-  g_return_if_fail (iter != NULL);
-  g_return_if_fail (value != NULL);
-
-  model = GTK_TREE_MODEL (token);
-  token = iter->user_data;
-  i = GPOINTER_TO_UINT (iter->user_data2);
-  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-  if (converters[entry->type].from_string == NULL)
-    return;
-  if (!converters[entry->type].from_string (value, &new))
-    return;
-  if (converters[entry->type].free != NULL)
-    converters[entry->type].free (entry->value);
-  entry->value = new;
-  klass = SWFEDIT_TOKEN_GET_CLASS (token);
-  if (klass->changed)
-    klass->changed (token, i);
-
-  path = gtk_tree_model_get_path (model, iter);
-  gtk_tree_model_row_changed (model, path, iter);
-  gtk_tree_path_free (path);
-}
-
-void
-swfedit_token_set_visible (SwfeditToken *token, guint i, gboolean visible)
-{
-  SwfeditTokenEntry *entry;
-  GtkTreeModel *model;
-  GtkTreePath *path;
-  GtkTreeIter iter;
-
-  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
-  g_return_if_fail (i < token->tokens->len);
-
-  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-  if (entry->visible == visible)
-    return;
-
-  entry->visible = visible;
-  iter.stamp = 0; /* FIXME */
-  iter.user_data = token;
-  iter.user_data2 = GINT_TO_POINTER (i);
-  while (token->parent) 
-    token = token->parent;
-  model = GTK_TREE_MODEL (token);
-  path = gtk_tree_model_get_path (model, &iter);
-  gtk_tree_model_row_changed (model, path, &iter);
-  gtk_tree_path_free (path);
-}
diff --git a/test/swfedit_token.h b/test/swfedit_token.h
deleted file mode 100644
index 448f4cb..0000000
--- a/test/swfedit_token.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef __SWFEDIT_TOKEN_H__
-#define __SWFEDIT_TOKEN_H__
-
-#include <gtk/gtk.h>
-#include <libswfdec/swfdec_rect.h>
-
-G_BEGIN_DECLS
-
-typedef enum {
-  SWFEDIT_TOKEN_OBJECT,
-  SWFEDIT_TOKEN_BINARY,
-  SWFEDIT_TOKEN_BIT,
-  SWFEDIT_TOKEN_UINT8,
-  SWFEDIT_TOKEN_UINT16,
-  SWFEDIT_TOKEN_UINT32,
-  SWFEDIT_TOKEN_STRING,
-  SWFEDIT_TOKEN_RECT,
-  SWFEDIT_TOKEN_RGB,
-  SWFEDIT_TOKEN_RGBA,
-  SWFEDIT_TOKEN_MATRIX,
-  SWFEDIT_TOKEN_CTRANS,
-  SWFEDIT_TOKEN_SCRIPT,
-  SWFEDIT_TOKEN_CLIPEVENTFLAGS,
-  SWFEDIT_N_TOKENS
-} SwfeditTokenType;
-
-typedef enum {
-  SWFEDIT_COLUMN_NAME,
-  SWFEDIT_COLUMN_VALUE_VISIBLE,
-  SWFEDIT_COLUMN_VALUE,
-  SWFEDIT_COLUMN_VALUE_EDITABLE
-} SwfeditColumn;
-
-typedef struct _SwfeditTokenEntry SwfeditTokenEntry;
-
-typedef struct _SwfeditToken SwfeditToken;
-typedef struct _SwfeditTokenClass SwfeditTokenClass;
-
-#define SWFEDIT_TYPE_TOKEN                    (swfedit_token_get_type())
-#define SWFEDIT_IS_TOKEN(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TOKEN))
-#define SWFEDIT_IS_TOKEN_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TOKEN))
-#define SWFEDIT_TOKEN(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TOKEN, SwfeditToken))
-#define SWFEDIT_TOKEN_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass))
-#define SWFEDIT_TOKEN_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass))
-
-struct _SwfeditTokenEntry {
-  char *		name;
-  SwfeditTokenType	type;
-  gpointer		value;
-  gboolean		visible;
-};
-
-struct _SwfeditToken {
-  GObject		object;
-
-  SwfeditToken *	parent;		/* parent of this token or NULL */
-  gchar *		name;		/* name of token */
-  GArray *		tokens;		/* of SwfeditTokenEntry */
-};
-
-struct _SwfeditTokenClass {
-  GObjectClass		object_class;
-
-  void			(* changed)		(SwfeditToken *		token,
-						 guint			id);
-};
-
-GType		swfedit_token_get_type		(void);
-
-gpointer	swfedit_token_new_token		(SwfeditTokenType	type);
-
-SwfeditToken *	swfedit_token_new		(void);
-void		swfedit_token_add		(SwfeditToken *		token,
-						 const char *		name,
-						 SwfeditTokenType	type,
-						 gpointer		value);
-void		swfedit_token_set		(SwfeditToken *		token,
-						 guint			i,
-						 gpointer		value);
-void		swfedit_token_set_iter		(SwfeditToken *		token,
-						 GtkTreeIter *		iter,
-						 const char *		value);
-void		swfedit_token_set_visible	(SwfeditToken *		token,
-						 guint			i,
-						 gboolean		visible);
-
-
-G_END_DECLS
-
-#endif
diff --git a/test/swfscript.c b/test/swfscript.c
deleted file mode 100644
index 4e2a9e4..0000000
--- a/test/swfscript.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/* Swfedit
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gtk/gtk.h>
-#include "libswfdec/swfdec_script_internal.h"
-#include "swfdec_out.h"
-#include "swfedit_file.h"
-
-/* the stuff we look for */
-guint *add_trace = NULL;
-
-typedef gboolean ( *SwfeditTokenForeachFunc) (SwfeditToken *token, guint idx, 
-    const char *name, SwfeditTokenType type, gconstpointer value, gpointer data);
-
-static gboolean
-swfedit_token_foreach (SwfeditToken *token, SwfeditTokenForeachFunc func, 
-    gpointer data)
-{
-  SwfeditTokenEntry *entry;
-  guint i;
-
-  g_return_val_if_fail (SWFEDIT_IS_TOKEN (token), FALSE);
-  g_return_val_if_fail (func != NULL, FALSE);
-
-  for (i = 0; i < token->tokens->len; i++) {
-    entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
-    if (!func (token, i, entry->name, entry->type, entry->value, data))
-      return FALSE;
-    if (entry->type == SWFEDIT_TOKEN_OBJECT) {
-      if (!swfedit_token_foreach (entry->value, func, data))
-	return FALSE;
-    }
-  }
-  return TRUE;
-}
-
-typedef struct {
-  guint			offset;			/* offset in bytes from start of script */
-  guint			new_offset;		/* new offset in bytes from start of script */
-  guint			new_actions;		/* number of actions in new script */
-} Action;
-
-typedef struct {
-  SwfdecScript *	script;			/* the original script */
-  SwfdecOut *		out;			/* output for new script or NULL when buffer is set */
-  SwfdecBuffer *	buffer;			/* buffer containing new script or NULL while constructing */
-  GArray *		actions;		/* all actions in the script */
-} State;
-
-static gboolean
-action_in_array (guint *array, guint action)
-{
-  if (array == NULL)
-    return FALSE;
-  while (*array != 0) {
-    if (*array == action)
-      return TRUE;
-    array++;
-  }
-  return FALSE;
-}
-
-static guint
-lookup_offset (GArray *array, guint offset)
-{
-  guint i;
-  for (i = 0; i < array->len; i++) {
-    Action *action = &g_array_index (array, Action, i);
-    if (action->offset == offset)
-      return action->new_offset;
-  }
-  g_assert_not_reached ();
-  return 0;
-}
-
-static gboolean
-fixup_jumps_foreach (gconstpointer bytecode, guint action,
-        const guint8 *data, guint len, gpointer user_data)
-{
-  State *state = user_data;
-    
-  if (action == 0x99 || action == 0x9d) {
-    guint offset = (guint8 *) bytecode - state->script->buffer->data;
-    guint jump_offset = offset + 5 + GINT16_FROM_LE (*((gint16 *) data));
-    offset = lookup_offset (state->actions, offset);
-    jump_offset = lookup_offset (state->actions, jump_offset);
-    *((gint16 *) &state->buffer->data[offset + 3]) = 
-      GINT16_TO_LE (jump_offset - offset - 5);
-  }
-  if (action == 0x8a || action == 0x8d) {
-    Action *cur = NULL; /* silence gcc */
-    guint id = action == 0x8a ? 2 : 0;
-    guint i, count;
-    guint offset = (guint8 *) bytecode - state->script->buffer->data;
-    for (i = 0; i < state->actions->len; i++) {
-      cur = &g_array_index (state->actions, Action, i);
-      if (cur->offset == offset) {
-	offset = cur->new_offset;
-	break;
-      }
-    }
-    g_assert (i < state->actions->len);
-    i = data[id];
-    count = cur->new_actions - 1; /* FIXME: only works as long as we append actions */
-    while (i > 0) {
-      cur++;
-      count += cur->new_actions;
-      i--;
-    }
-    g_assert (count < 256);
-    state->buffer->data[offset + 3 + id] = count;
-  }
-  return TRUE;
-}
-
-static gboolean
-modify_script_foreach (gconstpointer bytecode, guint action,
-        const guint8 *data, guint len, gpointer user_data)
-{
-  Action next;
-  State *state = user_data;
-    
-  next.offset = (guint8 *) bytecode - state->script->buffer->data;
-  next.new_offset = swfdec_out_get_bits (state->out) / 8;
-  next.new_actions = 1;
-  swfdec_out_put_u8 (state->out, action);
-  if (action & 0x80) {
-    swfdec_out_put_u16 (state->out, len);
-    swfdec_out_put_data (state->out, data, len);
-  }
-  if (action_in_array (add_trace, action)) {
-    swfdec_out_put_u8 (state->out, 0x4c); /* PushDuplicate */
-    swfdec_out_put_u8 (state->out, 0x26); /* Trace */
-    next.new_actions += 2;
-  }
-  g_array_append_val (state->actions, next);
-  return TRUE;
-}
-
-static gboolean
-modify_file (SwfeditToken *token, guint idx, const char *name, 
-    SwfeditTokenType type, gconstpointer value, gpointer data)
-{
-  Action end;
-  SwfdecScript *script;
-  State state;
-
-  if (type != SWFEDIT_TOKEN_SCRIPT)
-    return TRUE;
-
-  state.script = (SwfdecScript *) value;
-  state.out = swfdec_out_open ();
-  state.buffer = NULL;
-  state.actions = g_array_new (FALSE, FALSE, sizeof (Action));
-  swfdec_script_foreach (state.script, modify_script_foreach, &state);
-  /* compute end offset */
-  end.offset = g_array_index (state.actions, Action, state.actions->len - 1).offset;
-  if (state.script->buffer->data[end.offset] & 0x80) {
-    end.offset += GUINT16_FROM_LE (*((guint16* ) &state.script->buffer->data[end.offset + 1])) + 3;
-  } else {
-    end.offset++;
-  }
-  end.new_offset = swfdec_out_get_bits (state.out) / 8;
-  end.new_actions = 0;
-  g_array_append_val (state.actions, end);
-#if 0
-  {
-    guint i;
-    for (i = 0; i < state.actions->len; i++) {
-      Action *action = &g_array_index (state.actions, Action, i);
-      g_print ("%u  %u => %u  (%u actions)\n", i, action->offset, 
-	  action->new_offset, action->new_actions);
-    }
-  }
-#endif
-  /* maybe append 0 byte */
-  if (end.offset + 1 == state.script->buffer->length) {
-    swfdec_out_put_u8 (state.out, 0);
-  } else {
-    g_assert (end.offset == state.script->buffer->length);
-  }
-  state.buffer = swfdec_out_close (state.out);
-  state.out = NULL;
-  swfdec_script_foreach (state.script, fixup_jumps_foreach, &state);
-  g_array_free (state.actions, TRUE);
-#if 0
-  g_print ("got a new script in %u bytes - old script was %u bytes\n", 
-      state.buffer->length, state.script->buffer->length);
-#endif
-  script = swfdec_script_new (state.buffer, state.script->name, state.script->version);
-  g_assert (script);
-  swfedit_token_set (token, idx, script);
-
-  return TRUE;
-}
-
-static guint *
-string_to_action_list (const char *list)
-{
-  char **actions = g_strsplit (list, ",", -1);
-  guint *ret;
-  guint i, len;
-
-  len = g_strv_length (actions);
-  ret = g_new (guint, len + 1);
-  ret[len] = 0;
-  for (i = 0; i < len; i++) {
-    ret[i] = swfdec_action_get_from_name (actions[i]);
-    if (ret[i] == 0) {
-      g_printerr ("No such action \"%s\"\n", actions[i]);
-      g_free (actions);
-      g_free (ret);
-      return NULL;
-    }
-  }
-  g_free (actions);
-  return ret;
-}
-
-int
-main (int argc, char **argv)
-{
-  SwfeditFile *file;
-  GError *error = NULL;
-  char *add_trace_s = NULL;
-  GOptionEntry options[] = {
-    { "add-trace", 't', 0, G_OPTION_ARG_STRING, &add_trace_s, "list of actions to trace", "ACTION, ACTION" },
-    { NULL }
-  };
-  GOptionContext *ctx;
-
-  ctx = g_option_context_new ("");
-  g_option_context_add_main_entries (ctx, options, "options");
-  g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
-  g_option_context_parse (ctx, &argc, &argv, &error);
-  g_option_context_free (ctx);
-  if (error) {
-    g_printerr ("error parsing arguments: %s\n", error->message);
-    g_error_free (error);
-    return 1;
-  }
-
-  if (argc < 2) {
-    g_printerr ("Usage: %s FILENAME [OUTPUT-FILENAME]\n", argv[0]);
-    return 1;
-  }
-  if (add_trace_s) {
-    add_trace = string_to_action_list (add_trace_s);
-    g_free (add_trace_s);
-    if (add_trace == NULL)
-      return 1;
-  }
-  file = swfedit_file_new (argv[1], &error);
-  if (file == NULL) {
-    g_printerr ("error opening file %s: %s\n", argv[1], error->message);
-    g_error_free (error);
-    return 1;
-  }
-  if (!swfedit_token_foreach (SWFEDIT_TOKEN (file), modify_file, NULL)) {
-    g_printerr ("modifying file %s failed.\n", argv[1]);
-    g_object_unref (file);
-    return 1;
-  }
-  g_free (file->filename);
-  if (argc > 2) {
-    file->filename = g_strdup (argv[2]);
-  } else {
-    file->filename = g_strdup_printf ("%s.out.swf", argv[1]);
-  }
-  if (!swfedit_file_save (file, &error)) {
-    g_printerr ("Error saving file: %s\n", error->message);
-    g_error_free (error);
-  }
-  g_print ("saved modified file to %s\n", file->filename);
-  g_object_unref (file);
-  return 0;
-}
-
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644
index 0000000..9f6d925
--- /dev/null
+++ b/tools/.gitignore
@@ -0,0 +1,17 @@
+*~
+.deps
+.libs
+
+Makefile
+Makefile.in
+*.lo
+*.o
+
+libswfedit.la
+
+dump
+parse
+swfdec-extract
+swfedit
+swfscript
+crashfinder
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..9064878
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,41 @@
+if WITH_GTK
+noinst_LTLIBRARIES = libswfedit.la
+noinst_PROGRAMS = swfdec-extract dump swfedit swfscript crashfinder
+else
+noinst_PROGRAMS = swfdec-extract dump crashfinder
+endif
+
+crashfinder_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+crashfinder_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS)
+crashfinder_SOURCES = crashfinder.c
+
+dump_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS)
+dump_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
+
+swfdec_extract_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS)
+swfdec_extract_LDFLAGS = $(SWFDEC_LIBS) $(CAIRO_LIBS)
+
+libswfedit_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(GTK_CFLAGS)
+libswfedit_la_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS)
+
+swfedit_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(GTK_CFLAGS)
+swfedit_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS)
+swfedit_LDADD = libswfedit.la
+
+swfscript_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS) $(GTK_CFLAGS)
+swfscript_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS)
+swfscript_LDADD = libswfedit.la
+
+libswfedit_la_SOURCES = \
+	swfdec_out.c \
+	swfedit_file.c \
+	swfedit_list.c \
+	swfedit_tag.c \
+	swfedit_token.c
+
+noinst_HEADERS = \
+	swfdec_out.h \
+	swfedit_file.h \
+	swfedit_list.h \
+	swfedit_tag.h \
+	swfedit_token.h
diff --git a/tools/crashfinder.c b/tools/crashfinder.c
new file mode 100644
index 0000000..3c4a4a7
--- /dev/null
+++ b/tools/crashfinder.c
@@ -0,0 +1,157 @@
+/* Swfdec
+ * Copyright (C) 2007 Pekka Lampila <pekka.lampila at iki.fi>
+ *               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 <libswfdec/swfdec.h>
+
+int
+main (int argc, char **argv)
+{
+  GOptionContext *context;
+  GError *err;
+  SwfdecPlayer *player;
+  SwfdecLoader *loader;
+  guint i;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  gboolean aborts;
+  glong play_per_file = 30;
+  glong max_per_file = 60;
+  glong max_per_advance = 10;
+  GTimer *timer;
+  char **filenames = NULL;
+  const GOptionEntry entries[] = {
+    {
+      "play-time", 'p', 0, G_OPTION_ARG_INT, &play_per_file,
+      "How many seconds will be played from each file (default 30)", NULL
+    },
+    {
+      "max-per-file", '\0', 0, G_OPTION_ARG_INT, &max_per_file,
+      "Maximum runtime in seconds allowed for each file (default 60)", NULL
+    },
+    {
+      "max-per-advance", '\0', 0, G_OPTION_ARG_INT, &max_per_advance,
+      "Maximum runtime in seconds allowed for each advance (default 10)", NULL
+    },
+    {
+      G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
+      NULL, "<INPUT FILE> <OUTPUT FILE>"
+    },
+    {
+      NULL
+    }
+  };
+
+  // init
+  swfdec_init ();
+
+  // read command line params
+  context = g_option_context_new ("Run a Flash file trying to crash Swfdec");
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  if (g_option_context_parse (context, &argc, &argv, &err) == FALSE) {
+    g_printerr ("Couldn't parse command-line options: %s\n", err->message);
+    g_error_free (err);
+    return 1;
+  }
+
+  if (filenames == NULL || g_strv_length (filenames) < 1) {
+    g_printerr ("At least one input filename is required\n");
+    return 1;
+  }
+
+  // make them milliseconds
+  play_per_file *= 1000;
+  max_per_file *= 1000;
+  max_per_advance *= 1000;
+
+  // create surface
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+  cr = cairo_create (surface);
+
+  aborts = FALSE;
+  for (i = 0; i < g_strv_length (filenames); i++)
+  {
+    glong played, advance, elapsed;
+
+    g_print ("Running: %s\n", filenames[i]);
+
+    // start timer
+    timer = g_timer_new ();
+
+    // create player
+    loader = swfdec_file_loader_new (filenames[i]);
+    player = swfdec_player_new (NULL);
+
+    if (loader->error) {
+      g_printerr ("Error loading %s: %s\n", filenames[i], loader->error);
+      g_object_unref (loader);
+      continue;
+    }
+
+    swfdec_player_set_loader (player, loader);
+
+    // loop until we have played what we wanted, or timelimit is hit
+    played = 0;
+    elapsed = 0;
+    while (played < play_per_file &&
+	!swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player)))
+    {
+      elapsed = (glong)(g_timer_elapsed (timer, NULL) * 1000);
+      if (elapsed >= max_per_file)
+	break;
+      swfdec_player_set_maximum_runtime (player,
+	  MIN (max_per_advance, max_per_file - elapsed));
+
+      advance = swfdec_player_get_next_event (player);
+      if (advance == -1)
+	break;
+      swfdec_player_advance (player, advance);
+
+      swfdec_player_render (player, cr, 0, 0, 0, 0);
+
+      played += advance;
+    }
+
+    if (elapsed >= max_per_file ||
+	swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player))) {
+      g_print ("Aborted: %s\n", filenames[i]);
+      aborts = TRUE;
+    } else {
+      g_print ("Finished: %s\n", filenames[i]);
+    }
+
+    // clean up
+    g_object_unref (player);
+    g_timer_destroy (timer);
+  }
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+
+  if (aborts) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
diff --git a/tools/dump.c b/tools/dump.c
new file mode 100644
index 0000000..efea56d
--- /dev/null
+++ b/tools/dump.c
@@ -0,0 +1,448 @@
+/* Swfdec
+ * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
+ *		 2005-2006 Eric Anholt <eric at anholt.net>
+ *		 2006-2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 <stdio.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <libswfdec/swfdec.h>
+#include <libswfdec/swfdec_button.h>
+#include <libswfdec/swfdec_text_field.h>
+#include <libswfdec/swfdec_font.h>
+#include <libswfdec/swfdec_image.h>
+#include <libswfdec/swfdec_movie.h>
+#include <libswfdec/swfdec_player_internal.h>
+#include <libswfdec/swfdec_sprite.h>
+#include <libswfdec/swfdec_shape.h>
+#include <libswfdec/swfdec_sound.h>
+#include <libswfdec/swfdec_swf_decoder.h>
+#include <libswfdec/swfdec_resource.h>
+#include <libswfdec/swfdec_tag.h>
+#include <libswfdec/swfdec_text.h>
+
+static gboolean verbose = FALSE;
+
+static const char *
+get_audio_format_name (guint codec)
+{
+  switch (codec) {
+    case SWFDEC_AUDIO_CODEC_ADPCM:
+      return "ADPCM";
+    case SWFDEC_AUDIO_CODEC_MP3:
+      return "MP3";
+    case SWFDEC_AUDIO_CODEC_UNCOMPRESSED:
+      return "uncompressed";
+    case SWFDEC_AUDIO_CODEC_NELLYMOSER:
+      return "Nellymoser";
+    default:
+      return "Unknown";
+  }
+}
+
+static void
+dump_sound (SwfdecSound *sound)
+{
+  g_print ("  codec: %s\n", get_audio_format_name (sound->codec));
+  if (verbose) {
+    g_print ("  format: %s\n", swfdec_audio_format_to_string (sound->format));
+    g_print ("  samples: %u (%gs)\n", sound->n_samples, 
+	(double) sound->n_samples / swfdec_audio_format_get_rate (sound->format));
+  }
+}
+
+static void
+dump_sprite (SwfdecSwfDecoder *dec, SwfdecSprite *s)
+{
+  if (!verbose) {
+    g_print ("  %u frames\n", s->n_frames);
+  } else {
+    guint i, j, tag;
+    SwfdecBuffer *buffer;
+    SwfdecSound *sound = NULL;
+
+    for (i = 0; i < s->n_frames; i++) {
+      SwfdecSpriteFrame *frame = &s->frames[i];
+      if (frame->sound_head != sound &&
+	  frame->sound_block != NULL) {
+	sound = frame->sound_head;
+	for (j = i; j < s->n_frames; j++) {
+	  SwfdecSpriteFrame *cur = &s->frames[i];
+	  if (cur->sound_head != sound)
+	    break;
+	}
+	if (sound)
+	  g_print ("   %4u -%4u  sound: %s %s\n", i, j, 
+	      get_audio_format_name (sound->codec),
+	      swfdec_audio_format_to_string (sound->format));
+      }
+    }
+
+    j = 0;
+    for (i = 0; ; i++) {
+      if (!swfdec_sprite_get_action (s, i, &tag, &buffer))
+	break;
+      switch (tag) {
+	case SWFDEC_TAG_DOACTION:
+	  g_print ("   %4u script\n", j);
+	  break;
+	case SWFDEC_TAG_PLACEOBJECT2:
+	case SWFDEC_TAG_PLACEOBJECT3:
+	  {
+	    SwfdecBits bits;
+	    gboolean has_char, is_move;
+	    guint depth;
+
+	    swfdec_bits_init (&bits, buffer);
+	    swfdec_bits_getbits (&bits, 6);
+	    has_char = swfdec_bits_getbit (&bits);
+	    is_move = swfdec_bits_getbit (&bits);
+	    if (tag == SWFDEC_TAG_PLACEOBJECT3)
+	      swfdec_bits_get_u8 (&bits);
+	    depth = swfdec_bits_get_u16 (&bits);
+	    g_print ("   %4u %5u %s", j, depth, is_move ? "move" : "place");
+	    if (has_char) {
+	      SwfdecCharacter *c;
+	      c = swfdec_swf_decoder_get_character (dec, swfdec_bits_get_u16 (&bits));
+	      if (c)
+		g_print (" %s %u", G_OBJECT_TYPE_NAME (c), c->id);
+	    }
+	    g_print ("\n");
+	  }
+	  break;
+	case SWFDEC_TAG_REMOVEOBJECT:
+	case SWFDEC_TAG_REMOVEOBJECT2:
+	  {
+	    SwfdecBits bits;
+	    swfdec_bits_init (&bits, buffer);
+	    if (tag == SWFDEC_TAG_REMOVEOBJECT)
+	      swfdec_bits_get_u16 (&bits);
+	    g_print ("   %4u %5u remove\n", j, swfdec_bits_get_u16 (&bits));
+	  }
+	  break;
+	case SWFDEC_TAG_SHOWFRAME:
+	  j++;
+	  break;
+	case SWFDEC_TAG_STARTSOUND:
+	  /* FIXME add info about what sound etc */
+	  g_print ("   %4u start sound\n", j);
+	  break;
+	case SWFDEC_TAG_EXPORTASSETS:
+	  g_print ("   %4u export\n", j);
+	  break;
+	case SWFDEC_TAG_DOINITACTION:
+	  g_print ("   %4u init action\n", j);
+	  break;
+	default:
+	  g_assert_not_reached ();
+      }
+    }
+  }
+}
+
+static void
+dump_path (cairo_path_t *path)
+{
+  int i;
+  cairo_path_data_t *data = path->data;
+  const char *name;
+
+  for (i = 0; i < path->num_data; i++) {
+    name = NULL;
+    switch (data[i].header.type) {
+      case CAIRO_PATH_CURVE_TO:
+	g_print ("      curve %g %g (%g %g . %g %g)\n",
+	    data[i + 3].point.x, data[i + 3].point.y,
+	    data[i + 1].point.x, data[i + 1].point.y,
+	    data[i + 2].point.x, data[i + 2].point.y);
+	i += 3;
+	break;
+      case CAIRO_PATH_LINE_TO:
+	name = "line ";
+      case CAIRO_PATH_MOVE_TO:
+	if (!name)
+	  name = "move ";
+	i++;
+	g_print ("      %s %g %g\n", name, data[i].point.x, data[i].point.y);
+	break;
+      case CAIRO_PATH_CLOSE_PATH:
+	g_print ("      close\n");
+	break;
+      default:
+	g_assert_not_reached ();
+	break;
+    }
+  }
+}
+
+static void
+dump_shape (SwfdecShape *shape)
+{
+  GSList *walk;
+
+  for (walk = shape->draws; walk; walk = walk->next) {
+    if (SWFDEC_IS_PATTERN (walk->data)) {
+      SwfdecPattern *pattern = walk->data;
+      char *str = swfdec_pattern_to_string (pattern);
+      g_print ("%s\n", str);
+      g_free (str);
+      if (verbose) {
+	g_print ("        %g %g  %g %g  %g %g\n", 
+	    pattern->start_transform.xx, pattern->start_transform.xy,
+	    pattern->start_transform.yx, pattern->start_transform.yy,
+	    pattern->start_transform.x0, pattern->start_transform.y0);
+      }
+    } else if (SWFDEC_IS_STROKE (walk->data)) {
+      SwfdecStroke *line = walk->data;
+      g_print ("line (width %u, color #%08X)\n", line->start_width, line->start_color);
+    } else {
+      g_print ("not filled\n");
+    }
+    if (verbose) {
+      dump_path (&SWFDEC_DRAW (walk->data)->path);
+    }
+  }
+}
+
+static void
+dump_text_field (SwfdecTextField *text)
+{
+  g_print ("  %s\n", text->input ? text->input : "");
+  if (verbose) {
+    if (text->variable)
+      g_print ("  variable %s\n", text->variable);
+    else
+      g_print ("  no variable\n");
+  }
+}
+
+static void
+dump_text (SwfdecText *text)
+{
+  guint i;
+  gunichar2 uni[text->glyphs->len];
+  char *s;
+
+  for (i = 0; i < text->glyphs->len; i++) {
+    SwfdecTextGlyph *glyph = &g_array_index (text->glyphs, SwfdecTextGlyph, i);
+    uni[i] = g_array_index (glyph->font->glyphs, SwfdecFontEntry, glyph->glyph).value;
+    if (uni[i] == 0)
+      goto fallback;
+  }
+  s = g_utf16_to_utf8 (uni, text->glyphs->len, NULL, NULL, NULL);
+  if (s == NULL)
+    goto fallback;
+  g_print ("  text: %s\n", s);
+  g_free (s);
+  return;
+
+fallback:
+  g_print ("  %u characters\n", text->glyphs->len);
+}
+
+static void
+dump_font (SwfdecFont *font)
+{
+  unsigned int i;
+  if (font->name)
+    g_print ("  %s\n", font->name);
+  g_print ("  %u characters\n", font->glyphs->len);
+  if (verbose) {
+    for (i = 0; i < font->glyphs->len; i++) {
+      gunichar2 c = g_array_index (font->glyphs, SwfdecFontEntry, i).value;
+      char *s;
+      if (c == 0 || (s = g_utf16_to_utf8 (&c, 1, NULL, NULL, NULL)) == NULL) {
+	g_print (" ");
+      } else {
+	g_print ("%s ", s);
+	g_free (s);
+      }
+    }
+    g_print ("\n");
+  }
+}
+
+static void
+dump_button (SwfdecButton *button)
+{
+}
+
+static const char *
+get_image_type_name (SwfdecImageType type)
+{
+  switch (type) {
+    case SWFDEC_IMAGE_TYPE_JPEG:
+      return "JPEG with global table";
+    case SWFDEC_IMAGE_TYPE_JPEG2:
+      return "JPEG";
+    case SWFDEC_IMAGE_TYPE_JPEG3:
+      return "JPEG with alpha";
+    case SWFDEC_IMAGE_TYPE_LOSSLESS:
+      return "lossless";
+    case SWFDEC_IMAGE_TYPE_LOSSLESS2:
+      return "lossless with alpha";
+    case SWFDEC_IMAGE_TYPE_PNG:
+      return "PNG";
+    case SWFDEC_IMAGE_TYPE_UNKNOWN:
+    default:
+      g_assert_not_reached ();
+      return "Unknown";
+  }
+}
+
+static void
+dump_image (SwfdecImage *image)
+{
+  cairo_surface_destroy (swfdec_image_create_surface (image));
+  g_print ("  %s %u x %u\n", get_image_type_name (image->type),
+      image->width, image->height);
+}
+
+static void 
+dump_object (gpointer value, gpointer dec)
+{
+  SwfdecCharacter *c = value;
+
+  g_print ("%d: %s\n", c->id, G_OBJECT_TYPE_NAME (c));
+  if (verbose && SWFDEC_IS_GRAPHIC (c)) {
+    SwfdecGraphic *graphic = SWFDEC_GRAPHIC (c);
+    g_print ("  extents: %g %g  %g %g\n", graphic->extents.x0, graphic->extents.y0,
+	graphic->extents.x1, graphic->extents.y1);
+  }
+  if (SWFDEC_IS_IMAGE (c)) {
+    dump_image (SWFDEC_IMAGE (c));
+  }
+  if (SWFDEC_IS_SPRITE (c)) {
+    dump_sprite (dec, SWFDEC_SPRITE (c));
+  }
+  if (SWFDEC_IS_SHAPE(c)) {
+    dump_shape(SWFDEC_SHAPE(c));
+  }
+  if (SWFDEC_IS_TEXT (c)) {
+    dump_text (SWFDEC_TEXT (c));
+  }
+  if (SWFDEC_IS_TEXT_FIELD (c)) {
+    dump_text_field (SWFDEC_TEXT_FIELD (c));
+  }
+  if (SWFDEC_IS_FONT (c)) {
+    dump_font (SWFDEC_FONT (c));
+  }
+  if (SWFDEC_IS_BUTTON (c)) {
+    dump_button (SWFDEC_BUTTON (c));
+  }
+  if (SWFDEC_IS_SOUND (c)) {
+    dump_sound (SWFDEC_SOUND (c));
+  }
+}
+
+static void 
+enqueue (gpointer key, gpointer value, gpointer listp)
+{
+  GList **list = listp;
+
+  *list = g_list_prepend (*list, value);
+}
+
+static int
+sort_by_id (gconstpointer a, gconstpointer b)
+{
+  if (SWFDEC_CHARACTER (a)->id < SWFDEC_CHARACTER (b)->id)
+    return -1;
+  return 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+  SwfdecSwfDecoder *s;
+  SwfdecPlayer *player;
+  GError *error = NULL;
+  GOptionEntry options[] = {
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "bew verbose", NULL },
+    { NULL }
+  };
+  GOptionContext *ctx;
+  GList *list = NULL;
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, "options");
+  g_option_context_parse (ctx, &argc, &argv, &error);
+  g_option_context_free (ctx);
+  if (error) {
+    g_printerr ("Error parsing command line arguments: %s\n", error->message);
+    g_error_free (error);
+    return 1;
+  }
+
+  swfdec_init();
+
+  if(argc < 2){
+    g_print ("usage: %s [OPTIONS] file\n", argv[0]);
+    return 0;
+  }
+
+  player = swfdec_player_new_from_file (argv[1]);
+  if (player->priv->resource->loader->error) {
+    g_printerr ("Couldn't open file \"%s\": %s\n", argv[1], player->priv->resource->loader->error);
+    g_object_unref (player);
+    return 1;
+  }
+  /* FIXME: HACK! */
+  swfdec_player_advance (player, 0);
+  if (!swfdec_player_is_initialized (player)) {
+    g_printerr ("File \"%s\" is not a SWF file\n", argv[1]);
+    g_object_unref (player);
+    player = NULL;
+    return 1;
+  }
+  s = (SwfdecSwfDecoder *) SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder;
+  /* FIXME: can happen after a _root.loadMovie() call */
+  if (!SWFDEC_IS_SWF_DECODER (s)) {
+    g_printerr ("Movie already unloaded from \"%s\"\n", argv[1]);
+    g_object_unref (player);
+    player = NULL;
+    return 1;
+  }
+
+  g_print ("file:\n");
+  g_print ("  version: %d\n", s->version);
+  g_print ("  rate   : %g fps\n",  SWFDEC_DECODER (s)->rate / 256.0);
+  g_print ("  size   : %ux%u pixels\n", SWFDEC_DECODER (s)->width, SWFDEC_DECODER (s)->height);
+  g_print ("objects:\n");
+  g_hash_table_foreach (s->characters, enqueue, &list);
+  list = g_list_sort (list, sort_by_id);
+  g_list_foreach (list, dump_object, s);
+  g_list_free (list);
+
+  g_print ("main sprite:\n");
+  dump_sprite (s, s->main_sprite);
+  g_object_unref (player);
+  s = NULL;
+  player = NULL;
+
+  return 0;
+}
+
diff --git a/tools/swfdec-extract.c b/tools/swfdec-extract.c
new file mode 100644
index 0000000..3edfd25
--- /dev/null
+++ b/tools/swfdec-extract.c
@@ -0,0 +1,301 @@
+/* Swfdec
+ * Copyright (C) 2006 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cairo.h>
+#ifdef CAIRO_HAS_SVG_SURFACE
+#  include <cairo-svg.h>
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+#  include <cairo-pdf.h>
+#endif
+#include <libswfdec/swfdec.h>
+#include <libswfdec/swfdec_audio_stream.h>
+#include <libswfdec/swfdec_button.h>
+#include <libswfdec/swfdec_graphic.h>
+#include <libswfdec/swfdec_image.h>
+#include <libswfdec/swfdec_player_internal.h>
+#include <libswfdec/swfdec_sound.h>
+#include <libswfdec/swfdec_sprite.h>
+#include <libswfdec/swfdec_sprite_movie.h>
+#include <libswfdec/swfdec_swf_decoder.h>
+#include <libswfdec/swfdec_resource.h>
+
+static SwfdecBuffer *
+encode_wav (SwfdecBuffer *buffer, SwfdecAudioFormat format)
+{
+  SwfdecBuffer *wav = swfdec_buffer_new_and_alloc (buffer->length + 44);
+  unsigned char *data;
+  guint i;
+
+  data = wav->data;
+  /* FIXME: too much magic in this memmove */
+  memmove (data, "RIFF----WAVEfmt \020\0\0\0"
+		 "\001\0ccRRRRbbbbAAbbdata", 40);
+  *(guint32 *) (void *) &data[4] = GUINT32_TO_LE (buffer->length + 36);
+  *(guint16 *) (void *) &data[22] = GUINT16_TO_LE (swfdec_audio_format_get_channels (format));
+  *(guint32 *) (void *) &data[24] = GUINT32_TO_LE (swfdec_audio_format_get_rate (format));
+  /* bits per sample */
+  i = swfdec_audio_format_is_16bit (format) ? 2 : 1;
+  *(guint16 *) (void *) &data[34] = GUINT16_TO_LE (i * 8);
+  /* block align */
+  i *= swfdec_audio_format_get_channels (format);
+  *(guint16 *) (void *) &data[32] = GUINT16_TO_LE (i);
+  /* bytes per second */
+  i *= swfdec_audio_format_get_rate (format);
+  *(guint32 *) (void *) &data[28] = GUINT32_TO_LE (i);
+  *(guint32 *) (void *) &data[40] = GUINT32_TO_LE (buffer->length);
+  data += 44;
+  if (swfdec_audio_format_is_16bit (format)) {
+    for (i = 0; i < buffer->length; i += 2) {
+      *(gint16 *) (void *) (data + i) = GINT16_TO_LE (*(gint16* ) (void *) (buffer->data + i));
+    }
+  } else {
+    memcpy (data, buffer->data, buffer->length);
+  }
+  return wav;
+}
+
+static gboolean
+export_sound (SwfdecSound *sound, const char *filename)
+{
+  GError *error = NULL;
+  SwfdecBuffer *wav, *buffer;
+  SwfdecAudioFormat format;
+
+  /* try to render the sound, that should decode it. */
+  buffer = swfdec_sound_get_decoded (sound, &format);
+  if (buffer == NULL) {
+    g_printerr ("Couldn't decode sound. For extraction of streams extract the sprite.\n");
+    return FALSE;
+  }
+  wav = encode_wav (buffer, format);
+  if (!g_file_set_contents (filename, (char *) wav->data, 
+	wav->length, &error)) {
+    g_printerr ("Couldn't save sound to file \"%s\": %s\n", filename, error->message);
+    swfdec_buffer_unref (wav);
+    g_error_free (error);
+    return FALSE;
+  }
+  swfdec_buffer_unref (wav);
+  return TRUE;
+}
+
+static gboolean
+export_sprite_sound (SwfdecSprite *sprite, const char *filename)
+{
+  GError *error = NULL;
+  guint i, depth;
+  SwfdecAudio *audio;
+  SwfdecBufferQueue *queue;
+  SwfdecBuffer *buffer, *wav;
+
+  for (i = 0; i < sprite->n_frames; i++) {
+    if (sprite->frames[i].sound_head)
+      break;
+  }
+  if (i >= sprite->n_frames) {
+    g_printerr ("No sound in sprite %u\n", SWFDEC_CHARACTER (sprite)->id);
+    return FALSE;
+  }
+  audio = swfdec_audio_stream_new (NULL, sprite, i);
+  i = 4096;
+  queue = swfdec_buffer_queue_new ();
+  while (i > 0) {
+    buffer = swfdec_buffer_new ();
+    buffer->data = g_malloc0 (i * 4);
+    buffer->length = i * 4;
+#if 0
+    if (i > 1234) {
+      swfdec_audio_render (audio, (gint16 *) buffer->data, 0, 1234);
+      swfdec_audio_render (audio, (gint16 *) buffer->data + 2468, 1234, i - 1234);
+    } else
+#endif
+    {
+      swfdec_audio_render (audio, (gint16 *) (void *) buffer->data, 0, i);
+    }
+    i = swfdec_audio_iterate (audio, i);
+    i = MIN (i, 4096);
+    swfdec_buffer_queue_push (queue, buffer);
+  }
+  depth = swfdec_buffer_queue_get_depth (queue);
+  if (depth == 0) {
+    swfdec_buffer_queue_unref (queue);
+    g_printerr ("Sprite contains no sound\n");
+    return FALSE;
+  }
+  buffer = swfdec_buffer_queue_pull (queue, depth);
+  swfdec_buffer_queue_unref (queue);
+  wav = encode_wav (buffer, swfdec_audio_format_new (44100, 2, TRUE));
+  swfdec_buffer_unref (buffer);
+  if (!g_file_set_contents (filename, (char *) wav->data, 
+	wav->length, &error)) {
+    g_printerr ("Couldn't save sound to file \"%s\": %s\n", filename, error->message);
+    swfdec_buffer_unref (wav);
+    g_error_free (error);
+    return FALSE;
+  }
+  swfdec_buffer_unref (wav);
+  return TRUE;
+}
+
+static cairo_surface_t *
+surface_create_for_filename (const char *filename, int width, int height)
+{
+  guint len = strlen (filename);
+  cairo_surface_t *surface;
+  if (FALSE) {
+#ifdef CAIRO_HAS_PDF_SURFACE
+  } else if (len >= 3 && g_ascii_strcasecmp (filename + len - 3, "pdf") == 0) {
+    surface = cairo_pdf_surface_create (filename, width, height);
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+  } else if (len >= 3 && g_ascii_strcasecmp (filename + len - 3, "svg") == 0) {
+    surface = cairo_svg_surface_create (filename, width, height);
+#endif
+  } else {
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+  }
+  return surface;
+}
+
+static gboolean
+surface_destroy_for_type (cairo_surface_t *surface, const char *filename)
+{
+  if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) {
+    cairo_status_t status = cairo_surface_write_to_png (surface, filename);
+    if (status != CAIRO_STATUS_SUCCESS) {
+      g_printerr ("Error saving file: %s\n", cairo_status_to_string (status));
+      cairo_surface_destroy (surface);
+      return FALSE;
+    }
+  }
+  cairo_surface_destroy (surface);
+  return TRUE;
+}
+
+static gboolean
+export_graphic (SwfdecGraphic *graphic, const char *filename)
+{
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  guint width, height;
+  const SwfdecColorTransform trans = { 256, 0, 256, 0, 256, 0, 256, 0 };
+
+  if (SWFDEC_IS_SPRITE (graphic)) {
+    g_printerr ("Sprites can not be exported\n");
+    return FALSE;
+  }
+  if (SWFDEC_IS_BUTTON (graphic)) {
+    g_printerr ("Buttons can not be exported\n");
+    return FALSE;
+  }
+  width = ceil (graphic->extents.x1 / SWFDEC_TWIPS_SCALE_FACTOR) 
+    - floor (graphic->extents.x0 / SWFDEC_TWIPS_SCALE_FACTOR);
+  height = ceil (graphic->extents.y1 / SWFDEC_TWIPS_SCALE_FACTOR) 
+    - floor (graphic->extents.y0 / SWFDEC_TWIPS_SCALE_FACTOR);
+  surface = surface_create_for_filename (filename, width, height);
+  cr = cairo_create (surface);
+  cairo_translate (cr, - floor (graphic->extents.x0 / SWFDEC_TWIPS_SCALE_FACTOR),
+    - floor (graphic->extents.y0 / SWFDEC_TWIPS_SCALE_FACTOR));
+  cairo_scale (cr, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR);
+  swfdec_graphic_render (graphic, cr, &trans, &graphic->extents);
+  cairo_show_page (cr);
+  cairo_destroy (cr);
+  return surface_destroy_for_type (surface, filename);
+}
+
+static gboolean
+export_image (SwfdecImage *image, const char *filename)
+{
+  cairo_surface_t *surface = swfdec_image_create_surface (image);
+
+  if (surface == NULL)
+    return FALSE;
+  return surface_destroy_for_type (surface, filename);
+}
+
+static void
+usage (const char *app)
+{
+  g_print ("usage: %s SWFFILE ID OUTFILE\n\n", app);
+}
+
+int
+main (int argc, char *argv[])
+{
+  SwfdecCharacter *character;
+  int ret = 0;
+  SwfdecPlayer *player;
+  glong id;
+
+  swfdec_init ();
+
+  if (argc != 4) {
+    usage (argv[0]);
+    return 0;
+  }
+
+  player = swfdec_player_new_from_file (argv[1]);
+  /* FIXME: HACK! */
+  swfdec_player_advance (player, 0);
+  if (!SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data)) {
+    g_printerr ("Error parsing file \"%s\"\n", argv[1]);
+    g_object_unref (player);
+    player = NULL;
+    return 1;
+  }
+  id = strtol (argv[2], NULL, 0);
+  if (id >= 0) {
+    character = swfdec_swf_decoder_get_character (
+	SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder),
+	id);
+  } else {
+    character = SWFDEC_CHARACTER (SWFDEC_SWF_DECODER (
+	  SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder)->main_sprite);
+  }
+  if (SWFDEC_IS_SPRITE (character)) {
+    if (!export_sprite_sound (SWFDEC_SPRITE (character), argv[3]))
+      ret = 1;
+  } else if (SWFDEC_IS_SOUND (character)) {
+    if (!export_sound (SWFDEC_SOUND (character), argv[3]))
+      ret = 1;
+  } else if (SWFDEC_IS_GRAPHIC (character)) {
+    if (!export_graphic (SWFDEC_GRAPHIC (character), argv[3]))
+      ret = 1;
+  } else if (SWFDEC_IS_IMAGE (character)) {
+    if (!export_image (SWFDEC_IMAGE (character), argv[3]))
+      ret = 1;
+  } else {
+    g_printerr ("id %ld does not specify an exportable object\n", id);
+    ret = 1;
+  }
+
+  g_object_unref (player);
+  player = NULL;
+
+  return ret;
+}
+
diff --git a/tools/swfdec_out.c b/tools/swfdec_out.c
new file mode 100644
index 0000000..ecf5a83
--- /dev/null
+++ b/tools/swfdec_out.c
@@ -0,0 +1,383 @@
+/* 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_get_bits (SwfdecOut *out)
+{
+  g_return_val_if_fail (out != NULL, 0);
+
+  return (out->ptr - out->data) * 8 + out->idx;
+}
+
+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_data (SwfdecOut *out, const guint8 *data, guint length)
+{
+  g_return_if_fail (out != NULL);
+
+  swfdec_out_prepare_bytes (out, length);
+  memcpy (out->ptr, data, length);
+  out->ptr += length;
+}
+
+void
+swfdec_out_put_buffer (SwfdecOut *out, SwfdecBuffer *buffer)
+{
+  g_return_if_fail (out != NULL);
+
+  swfdec_out_prepare_bytes (out, buffer->length);
+  memcpy (out->ptr, buffer->data, buffer->length);
+  out->ptr += buffer->length;
+}
+
+void
+swfdec_out_put_u8 (SwfdecOut *out, guint i)
+{
+  g_return_if_fail (i <= G_MAXUINT8);
+
+  swfdec_out_prepare_bytes (out, 1);
+  *out->ptr = i;
+  out->ptr++;
+}
+
+void
+swfdec_out_put_u16 (SwfdecOut *out, guint i)
+{
+  g_return_if_fail (i <= G_MAXUINT16);
+
+  swfdec_out_prepare_bytes (out, 2);
+  *(guint16 *)out->ptr = GUINT16_TO_LE (i);
+  out->ptr += 2;
+}
+
+void
+swfdec_out_put_u32 (SwfdecOut *out, guint i)
+{
+  g_return_if_fail (i <= G_MAXUINT32);
+
+  swfdec_out_prepare_bytes (out, 4);
+  *(guint32 *)out->ptr = GUINT32_TO_LE (i);
+  out->ptr += 4;
+}
+
+void
+swfdec_out_put_bit (SwfdecOut *out, gboolean bit)
+{
+  g_return_if_fail (out != NULL);
+
+  swfdec_out_put_bits (out, bit ? 1 : 0, 1);
+}
+
+void
+swfdec_out_put_bits (SwfdecOut *out, guint bits, guint n_bits)
+{
+  g_return_if_fail (out != NULL);
+
+  swfdec_out_ensure_bits (out, n_bits);
+
+  /* FIXME: implement this less braindead */
+  while (n_bits) {
+    guint bits_now = MIN (n_bits, 8 - out->idx);
+    guint value = bits >> (n_bits - bits_now);
+
+    /* clear data if necessary */
+    if (out->idx == 0)
+      *out->ptr = 0;
+    value &= (1 << bits_now) - 1;
+    value <<= 8 - out->idx - bits_now;
+    *out->ptr |= value;
+    out->idx += bits_now;
+    g_assert (out->idx <= 8);
+    if (out->idx == 8) {
+      out->ptr ++;
+      out->idx = 0;
+    }
+    n_bits -= bits_now;
+  }
+}
+
+void
+swfdec_out_put_sbits (SwfdecOut *out, int bits, guint n_bits)
+{
+  g_return_if_fail (out != NULL);
+  swfdec_out_put_bits (out, bits, n_bits);
+}
+
+void
+swfdec_out_put_string (SwfdecOut *out, const char *s)
+{
+  guint len;
+
+  g_return_if_fail (out != NULL);
+  g_return_if_fail (s != NULL);
+
+  len = strlen (s) + 1;
+
+  swfdec_out_prepare_bytes (out, len);
+  memcpy (out->ptr, s, len);
+  out->ptr += len;
+}
+
+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, const SwfdecRect *rect)
+{
+  int x0, x1, y0, y1;
+  guint req, tmp;
+
+  g_return_if_fail (out != NULL);
+  g_return_if_fail (rect != NULL);
+
+  x0 = rect->x0;
+  y0 = rect->y0;
+  x1 = rect->x1;
+  y1 = rect->y1;
+  req = swfdec_out_sbits_required (x0);
+  tmp = swfdec_out_sbits_required (y0);
+  req = MAX (req, tmp);
+  tmp = swfdec_out_sbits_required (x1);
+  req = MAX (req, tmp);
+  tmp = swfdec_out_sbits_required (y1);
+  req = MAX (req, tmp);
+  swfdec_out_syncbits (out);
+  swfdec_out_put_bits (out, req, 5);
+  swfdec_out_put_sbits (out, x0, req);
+  swfdec_out_put_sbits (out, x1, req);
+  swfdec_out_put_sbits (out, y0, req);
+  swfdec_out_put_sbits (out, y1, req);
+  swfdec_out_syncbits (out);
+}
+
+void
+swfdec_out_put_matrix (SwfdecOut *out, const cairo_matrix_t *matrix)
+{
+  int x, y;
+  unsigned int xbits, ybits;
+
+  if (matrix->xx != 1.0 || matrix->yy != 1.0) {
+    swfdec_out_put_bit (out, 1);
+    x = SWFDEC_DOUBLE_TO_FIXED (matrix->xx);
+    y = SWFDEC_DOUBLE_TO_FIXED (matrix->yy);
+    xbits = swfdec_out_sbits_required (x);
+    ybits = swfdec_out_sbits_required (y);
+    xbits = MAX (xbits, ybits);
+    swfdec_out_put_bits (out, xbits, 5);
+    swfdec_out_put_sbits (out, x, xbits);
+    swfdec_out_put_sbits (out, y, xbits);
+  } else {
+    swfdec_out_put_bit (out, 0);
+  }
+  if (matrix->xy != 0.0 || matrix->yx != 0.0) {
+    swfdec_out_put_bit (out, 1);
+    x = SWFDEC_DOUBLE_TO_FIXED (matrix->yx);
+    y = SWFDEC_DOUBLE_TO_FIXED (matrix->xy);
+    xbits = swfdec_out_sbits_required (x);
+    ybits = swfdec_out_sbits_required (y);
+    xbits = MAX (xbits, ybits);
+    swfdec_out_put_bits (out, xbits, 5);
+    swfdec_out_put_sbits (out, x, xbits);
+    swfdec_out_put_sbits (out, y, xbits);
+  } else {
+    swfdec_out_put_bit (out, 0);
+  }
+  x = matrix->x0;
+  y = matrix->y0;
+  xbits = swfdec_out_sbits_required (x);
+  ybits = swfdec_out_sbits_required (y);
+  xbits = MAX (xbits, ybits);
+  swfdec_out_put_bits (out, xbits, 5);
+  swfdec_out_put_sbits (out, x, xbits);
+  swfdec_out_put_sbits (out, y, xbits);
+  swfdec_out_syncbits (out);
+}
+
+void
+swfdec_out_put_color_transform (SwfdecOut *out, const SwfdecColorTransform *trans)
+{
+  gboolean has_add, has_mult;
+  unsigned int n_bits, tmp;
+
+  has_mult = trans->ra != 256 || trans->ga != 256 || trans->ba != 256 || trans->aa != 256;
+  has_add = trans->rb != 0 || trans->gb != 0 || trans->bb != 0 || trans->ab != 0;
+  if (has_mult) {
+    n_bits = swfdec_out_sbits_required (trans->ra);
+    tmp = swfdec_out_sbits_required (trans->ga);
+    n_bits = MAX (tmp, n_bits);
+    tmp = swfdec_out_sbits_required (trans->ba);
+    n_bits = MAX (tmp, n_bits);
+    tmp = swfdec_out_sbits_required (trans->aa);
+    n_bits = MAX (tmp, n_bits);
+  } else {
+    n_bits = 0;
+  }
+  if (has_add) {
+    tmp = swfdec_out_sbits_required (trans->rb);
+    n_bits = MAX (tmp, n_bits);
+    tmp = swfdec_out_sbits_required (trans->gb);
+    n_bits = MAX (tmp, n_bits);
+    tmp = swfdec_out_sbits_required (trans->bb);
+    n_bits = MAX (tmp, n_bits);
+    tmp = swfdec_out_sbits_required (trans->ab);
+    n_bits = MAX (tmp, n_bits);
+  }
+  if (n_bits >= (1 << 4))
+    n_bits = (1 << 4) - 1;
+  swfdec_out_put_bit (out, has_add);
+  swfdec_out_put_bit (out, has_mult);
+  swfdec_out_put_bits (out, n_bits, 4);
+  if (has_mult) {
+    swfdec_out_put_sbits (out, trans->ra, n_bits);
+    swfdec_out_put_sbits (out, trans->ga, n_bits);
+    swfdec_out_put_sbits (out, trans->ba, n_bits);
+    swfdec_out_put_sbits (out, trans->aa, n_bits);
+  }
+  if (has_add) {
+    swfdec_out_put_sbits (out, trans->rb, n_bits);
+    swfdec_out_put_sbits (out, trans->gb, n_bits);
+    swfdec_out_put_sbits (out, trans->bb, n_bits);
+    swfdec_out_put_sbits (out, trans->ab, n_bits);
+  }
+  swfdec_out_syncbits (out);
+}
+
+void
+swfdec_out_put_rgb (SwfdecOut *out, SwfdecColor color)
+{
+  g_return_if_fail (out != NULL);
+
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_R (color));
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_G (color));
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_B (color));
+}
+
+void
+swfdec_out_put_rgba (SwfdecOut *out, SwfdecColor color)
+{
+  g_return_if_fail (out != NULL);
+
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_R (color));
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_G (color));
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_B (color));
+  swfdec_out_put_u8 (out, SWFDEC_COLOR_A (color));
+}
+
diff --git a/tools/swfdec_out.h b/tools/swfdec_out.h
new file mode 100644
index 0000000..e343f9d
--- /dev/null
+++ b/tools/swfdec_out.h
@@ -0,0 +1,88 @@
+/* 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_color.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_get_bits		(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_data		(SwfdecOut *		out,
+						 const guint8 *		data,
+						 guint			length);
+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_string		(SwfdecOut *		out,
+						 const char *		s);
+
+void		swfdec_out_put_rgb		(SwfdecOut *		out,
+						 SwfdecColor		color);
+void		swfdec_out_put_rgba		(SwfdecOut *		out,
+						 SwfdecColor		color);
+void		swfdec_out_put_rect		(SwfdecOut *		out,
+						 const SwfdecRect *	rect);
+void		swfdec_out_put_matrix		(SwfdecOut *		out,
+						 const cairo_matrix_t *	matrix);
+void		swfdec_out_put_color_transform	(SwfdecOut *		out,
+						 const SwfdecColorTransform *trans);
+
+
+G_END_DECLS
+
+#endif
diff --git a/tools/swfedit.c b/tools/swfedit.c
new file mode 100644
index 0000000..24f2980
--- /dev/null
+++ b/tools/swfedit.c
@@ -0,0 +1,138 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include "swfedit_file.h"
+
+static void
+save (GtkButton *button, SwfeditFile *file)
+{
+  GtkWidget *dialog;
+  GError *error = NULL;
+
+  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_REJECT,
+      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, 
+      NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+  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_ACCEPT) {
+    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
+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_iter (SWFEDIT_TOKEN (file), &iter, new_text);
+}
+
+static gboolean
+open_window (char *filename)
+{
+  SwfeditFile *file;
+  GtkWidget *window, *scroll, *box, *button, *treeview;
+  GError *error = NULL;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  char *basename;
+
+  file = swfedit_file_new (filename, &error);
+  if (file == NULL) {
+    g_printerr ("Error opening file %s: %s\n", filename, error->message);
+    g_error_free (error);
+    return FALSE;
+  }
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  basename = g_path_get_basename (filename);
+  if (basename) {
+    gtk_window_set_title (GTK_WINDOW (window), basename);
+    g_free (basename);
+  }
+  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_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);
+
+  renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
+    "text", SWFEDIT_COLUMN_NAME, "sensitive", SWFEDIT_COLUMN_VALUE_EDITABLE, NULL);
+  gtk_tree_view_column_set_resizable (column, TRUE);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
+  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, 
+    "sensitive", SWFEDIT_COLUMN_VALUE_EDITABLE, NULL);
+  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;
+}
+
+int
+main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  if (argc <= 1) {
+    g_print ("Usage: %s FILENAME\n", argv[0]);
+    return 1;
+  }
+  if (open_window (argv[1])) {
+    gtk_main ();
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
diff --git a/tools/swfedit_file.c b/tools/swfedit_file.c
new file mode 100644
index 0000000..e257010
--- /dev/null
+++ b/tools/swfedit_file.c
@@ -0,0 +1,297 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <zlib.h>
+
+#include "libswfdec/swfdec_bits.h"
+#include "libswfdec/swfdec_buffer.h"
+#include "libswfdec/swfdec_debug.h"
+#include "libswfdec/swfdec_swf_decoder.h"
+#include "swfdec_out.h"
+#include "swfedit_file.h"
+#include "swfedit_tag.h"
+
+G_DEFINE_TYPE (SwfeditFile, swfedit_file, SWFEDIT_TYPE_TOKEN)
+
+static void
+swfedit_file_dispose (GObject *object)
+{
+  SwfeditFile *file = SWFEDIT_FILE (object);
+
+  g_free (file->filename);
+
+  G_OBJECT_CLASS (swfedit_file_parent_class)->dispose (object);
+}
+
+static void *
+zalloc (void *opaque, unsigned int items, unsigned int size)
+{
+  return g_malloc (items * size);
+}
+
+static void
+zfree (void *opaque, void *addr)
+{
+  g_free (addr);
+}
+
+static SwfdecBuffer *
+swfenc_file_inflate (SwfdecBits *bits, guint size)
+{
+  SwfdecBuffer *decoded, *encoded;
+  z_stream z;
+  int ret;
+
+  encoded = swfdec_bits_get_buffer (bits, -1);
+  if (encoded == NULL)
+    return NULL;
+  decoded = swfdec_buffer_new_and_alloc (size);
+  z.zalloc = zalloc;
+  z.zfree = zfree;
+  z.opaque = NULL;
+  z.next_in = encoded->data;
+  z.avail_in = encoded->length;
+  z.next_out = decoded->data;
+  z.avail_out = decoded->length;
+  ret = inflateInit (&z);
+  SWFDEC_DEBUG ("inflateInit returned %d", ret);
+  if (ret >= Z_OK) {
+    ret = inflate (&z, Z_SYNC_FLUSH);
+    SWFDEC_DEBUG ("inflate returned %d", ret);
+  }
+  inflateEnd (&z);
+  swfdec_buffer_unref (encoded);
+  if (ret < Z_OK) {
+    swfdec_buffer_unref (decoded);
+    return NULL;
+  }
+  return decoded;
+}
+
+static SwfdecBuffer *
+swf_parse_header1 (SwfeditFile *file, SwfdecBits *bits, GError **error)
+{
+  guint sig1, sig2, sig3, bytes_total;
+
+  sig1 = swfdec_bits_get_u8 (bits);
+  sig2 = swfdec_bits_get_u8 (bits);
+  sig3 = swfdec_bits_get_u8 (bits);
+  if ((sig1 != 'F' && sig1 != 'C') || sig2 != 'W' || sig3 != 'S') {
+    g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	"This is not a SWF file");
+    return NULL;
+  }
+
+  swfedit_token_add (SWFEDIT_TOKEN (file), "version", SWFEDIT_TOKEN_UINT8, 
+      GUINT_TO_POINTER (swfdec_bits_get_u8 (bits)));
+  bytes_total = swfdec_bits_get_u32 (bits) - 8;
+
+  if (sig1 == 'C') {
+    /* compressed */
+    SwfdecBuffer *ret = swfenc_file_inflate (bits, bytes_total);
+    if (ret == NULL)
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	  "Unable to uncompress file");
+    return ret;
+  } else {
+    SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, bytes_total);
+    if (ret == NULL)
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	  "File too small");
+    return ret;
+  }
+}
+
+static void
+swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits)
+{
+  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rect", SWFEDIT_TOKEN_RECT, NULL);
+  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rate", SWFEDIT_TOKEN_UINT16, NULL);
+  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "frames", SWFEDIT_TOKEN_UINT16, NULL);
+}
+
+static gboolean
+swfedit_file_parse (SwfeditFile *file, SwfdecBits *bits, GError **error)
+{
+  SwfdecBuffer *next;
+  
+  next = swf_parse_header1 (file, bits, error);
+  if (next == NULL)
+    return FALSE;
+  swfdec_bits_init (bits, next);
+  swf_parse_header2 (file, bits);
+
+  while (swfdec_bits_left (bits)) {
+    guint x = swfdec_bits_get_u16 (bits);
+    G_GNUC_UNUSED guint tag = (x >> 6) & 0x3ff;
+    guint tag_len = x & 0x3f;
+    SwfdecBuffer *buffer;
+    SwfeditTag *item;
+
+    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
+      buffer = swfdec_buffer_new ();
+    if (buffer == NULL) {
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	  "Invalid contents in file");
+      return FALSE;
+    }
+    item = swfedit_tag_new (SWFEDIT_TOKEN (file), tag, buffer);
+    swfedit_token_add (SWFEDIT_TOKEN (file), 
+	swfdec_swf_decoder_get_tag_name (tag), 
+	SWFEDIT_TOKEN_OBJECT, item);
+  }
+  swfdec_buffer_unref (next);
+  return TRUE;
+}
+
+static void
+swfedit_file_class_init (SwfeditFileClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = swfedit_file_dispose;
+}
+
+static void
+swfedit_file_init (SwfeditFile *s)
+{
+}
+
+SwfeditFile *
+swfedit_file_new (const char *filename, GError **error)
+{
+  SwfeditFile *file;
+  SwfdecBuffer *buffer;
+  SwfdecBits bits;
+  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 = absolute;
+  if (!swfedit_file_parse (file, &bits, error)) {
+    swfdec_buffer_unref (buffer);
+    g_object_unref (file);
+    return NULL;
+  }
+  swfdec_buffer_unref (buffer);
+  return file;
+}
+
+static SwfdecBuffer *
+swfedit_file_write (SwfeditFile *file)
+{
+  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);
+  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_unref (queue);
+  return swfdec_out_close (out);
+}
+
+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;
+}
+
+guint
+swfedit_file_get_version (SwfeditFile *file)
+{
+  SwfeditTokenEntry *entry;
+
+  g_return_val_if_fail (SWFEDIT_FILE (file), 3);
+
+  entry = &g_array_index (SWFEDIT_TOKEN (file)->tokens, SwfeditTokenEntry, 0);
+  return GPOINTER_TO_UINT (entry->value);
+}
+
diff --git a/tools/swfedit_file.h b/tools/swfedit_file.h
new file mode 100644
index 0000000..ecd096a
--- /dev/null
+++ b/tools/swfedit_file.h
@@ -0,0 +1,60 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_FILE_H__
+#define __SWFEDIT_FILE_H__
+
+#include <libswfdec/swfdec_rect.h>
+#include "swfedit_token.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SwfeditFile SwfeditFile;
+typedef struct _SwfeditFileClass SwfeditFileClass;
+
+#define SWFEDIT_TYPE_FILE                    (swfedit_file_get_type())
+#define SWFEDIT_IS_FILE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_FILE))
+#define SWFEDIT_IS_FILE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_FILE))
+#define SWFEDIT_FILE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_FILE, SwfeditFile))
+#define SWFEDIT_FILE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_FILE, SwfeditFileClass))
+#define SWFEDIT_FILE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_FILE, SwfeditFileClass))
+
+struct _SwfeditFile {
+  SwfeditToken		token;
+
+  char *		filename;	/* name this file is saved to */
+};
+
+struct _SwfeditFileClass {
+  SwfeditTokenClass	token_class;
+};
+
+GType		swfedit_file_get_type		(void);
+
+SwfeditFile *	swfedit_file_new		(const char *	filename,
+						 GError **	error);
+
+gboolean	swfedit_file_save		(SwfeditFile *	file,
+						 GError **	error);
+guint		swfedit_file_get_version	(SwfeditFile *	file);
+
+
+G_END_DECLS
+
+#endif
diff --git a/tools/swfedit_list.c b/tools/swfedit_list.c
new file mode 100644
index 0000000..45e0dd5
--- /dev/null
+++ b/tools/swfedit_list.c
@@ -0,0 +1,149 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfedit_list.h"
+
+G_DEFINE_TYPE (SwfeditList, swfedit_list, SWFEDIT_TYPE_TOKEN)
+
+static void
+swfedit_list_dispose (GObject *object)
+{
+  //SwfeditList *list = SWFEDIT_LIST (object);
+
+  G_OBJECT_CLASS (swfedit_list_parent_class)->dispose (object);
+}
+
+static void
+swfedit_list_changed (SwfeditToken *token, guint i)
+{
+  guint j;
+  SwfeditList *list = SWFEDIT_LIST (token);
+  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+
+  /* update visibility */
+  for (j = i + 1; j % list->n_defs != 0; j++) {
+    if (list->def[j].n_items == (j % list->n_defs) + 1) {
+      swfedit_token_set_visible (token, j, entry->value != NULL);
+    }
+  }
+  /* update length */
+  j = list->def[i % list->n_defs].n_items;
+  if (j != 0) {
+    entry = &g_array_index (token->tokens, 
+	SwfeditTokenEntry, j - 1);
+    if (entry->type == SWFEDIT_TOKEN_UINT32) {
+      SwfdecOut *out = swfdec_out_open ();
+      SwfdecBuffer *buffer;
+      swfedit_tag_write_token (token, out, i);
+      buffer = swfdec_out_close (out);
+      if (entry->value != GUINT_TO_POINTER (buffer->length)) {
+	swfedit_token_set (token, i / list->n_defs * list->n_defs + j - 1, 
+	    GUINT_TO_POINTER (buffer->length));
+      }
+      swfdec_buffer_unref (buffer);
+    }
+  }
+  /* maybe add items */
+  if (i == token->tokens->len - 1) {
+    for (j = 0; j < list->n_defs; j++) {
+      const SwfeditTagDefinition *def = &list->def[(j + 1) % list->n_defs];
+      swfedit_tag_add_token (SWFEDIT_TOKEN (list), def->name, def->type, def->hint);
+    }
+  }
+}
+
+static void
+swfedit_list_class_init (SwfeditListClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  SwfeditTokenClass *token_class = SWFEDIT_TOKEN_CLASS (klass);
+
+  object_class->dispose = swfedit_list_dispose;
+
+  token_class->changed = swfedit_list_changed;
+}
+
+static void
+swfedit_list_init (SwfeditList *list)
+{
+}
+
+static SwfeditList *
+swfedit_list_new_internal (const SwfeditTagDefinition *def)
+{
+  SwfeditList *list;
+
+  list = g_object_new (SWFEDIT_TYPE_LIST, NULL);
+  list->def = def;
+  for (; def->name; def++)
+    list->n_defs++;
+
+  return list;
+}
+
+SwfeditList *
+swfedit_list_new (const SwfeditTagDefinition *def)
+{
+  SwfeditList *list;
+
+  g_return_val_if_fail (def != NULL, NULL);
+
+  list = swfedit_list_new_internal (def);
+  swfedit_tag_add_token (SWFEDIT_TOKEN (list), def->name, def->type, def->hint);
+
+  return list;
+}
+
+SwfeditList *
+swfedit_list_new_read (SwfeditToken *parent, SwfdecBits *bits, const SwfeditTagDefinition *def)
+{
+  SwfeditList *list;
+  SwfeditTokenEntry *entry;
+  guint offset;
+
+  g_return_val_if_fail (bits != NULL, NULL);
+  g_return_val_if_fail (def != NULL, NULL);
+
+  list = swfedit_list_new_internal (def);
+  SWFEDIT_TOKEN (list)->parent = parent;
+  offset = 0;
+  while (TRUE) {
+    def = list->def;
+    swfedit_tag_read_tag (SWFEDIT_TOKEN (list), bits, def);
+    entry = &g_array_index (SWFEDIT_TOKEN (list)->tokens, SwfeditTokenEntry,
+	SWFEDIT_TOKEN (list)->tokens->len - 1);
+    if (GPOINTER_TO_UINT (entry->value) == 0)
+      break;
+
+    def++;
+    for (;def->name != NULL; def++) {
+      SwfeditTagDefinition def2 = *def;
+      if (def2.n_items)
+	def2.n_items += offset;
+      swfedit_tag_read_tag (SWFEDIT_TOKEN (list), bits, &def2);
+    }
+    offset += list->n_defs;
+  }
+  return list;
+}
+
diff --git a/tools/swfedit_list.h b/tools/swfedit_list.h
new file mode 100644
index 0000000..e0666f7
--- /dev/null
+++ b/tools/swfedit_list.h
@@ -0,0 +1,61 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_LIST_H__
+#define __SWFEDIT_LIST_H__
+
+#include "swfdec_out.h"
+#include "swfedit_tag.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SwfeditList SwfeditList;
+typedef struct _SwfeditListClass SwfeditListClass;
+
+#define SWFEDIT_TYPE_LIST                    (swfedit_list_get_type())
+#define SWFEDIT_IS_LIST(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_LIST))
+#define SWFEDIT_IS_LIST_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_LIST))
+#define SWFEDIT_LIST(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_LIST, SwfeditList))
+#define SWFEDIT_LIST_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_LIST, SwfeditListClass))
+#define SWFEDIT_LIST_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_LIST, SwfeditListClass))
+
+struct _SwfeditList {
+  SwfeditToken			token;
+
+  const SwfeditTagDefinition *	def;	/* definition of our items */
+  guint				n_defs;	/* number of items in def */
+};
+
+struct _SwfeditListClass {
+  SwfeditTokenClass	token_class;
+};
+
+GType		swfedit_list_get_type	(void);
+
+SwfeditList *	swfedit_list_new	(const SwfeditTagDefinition *	def);
+SwfeditList *	swfedit_list_new_read	(SwfeditToken *			parent,
+					 SwfdecBits *			bits,
+					 const SwfeditTagDefinition *	def);
+
+SwfdecBuffer *	swfedit_list_write	(SwfeditList *			list);
+
+
+G_END_DECLS
+
+#endif
diff --git a/tools/swfedit_tag.c b/tools/swfedit_tag.c
new file mode 100644
index 0000000..4a4bf67
--- /dev/null
+++ b/tools/swfedit_tag.c
@@ -0,0 +1,507 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include <libswfdec/swfdec_bits.h>
+#include <libswfdec/swfdec_debug.h>
+#include <libswfdec/swfdec_script_internal.h>
+#include <libswfdec/swfdec_tag.h>
+#include "swfedit_tag.h"
+#include "swfdec_out.h"
+#include "swfedit_file.h"
+#include "swfedit_list.h"
+
+/*** LOAD/SAVE ***/
+
+static void
+swfedit_object_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  SwfdecBuffer *buffer;
+
+  g_assert (SWFEDIT_IS_TOKEN (data));
+  buffer = swfedit_tag_write (data);
+  swfdec_out_put_buffer (out, buffer);
+  swfdec_buffer_unref (buffer);
+}
+
+static gpointer
+swfedit_object_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return swfedit_list_new_read (token, bits, hint);
+}
+
+static void
+swfedit_binary_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_buffer (out, data);
+}
+
+static gpointer
+swfedit_binary_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, -1);
+  if (buffer == NULL)
+    buffer = swfdec_buffer_new ();
+  return buffer;
+}
+
+static void
+swfedit_bit_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_bit (out, data ? TRUE : FALSE);
+}
+
+static gpointer
+swfedit_bit_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER (swfdec_bits_getbit (bits) ? 1 : 0);
+}
+
+static void
+swfedit_u8_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_u8 (out, GPOINTER_TO_UINT (data));
+}
+
+static gpointer
+swfedit_u8_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER ((gulong) swfdec_bits_get_u8 (bits));
+}
+
+static void
+swfedit_u16_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_u16 (out, GPOINTER_TO_UINT (data));
+}
+
+static gpointer
+swfedit_u16_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits));
+}
+
+static void
+swfedit_u32_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_u32 (out, GPOINTER_TO_UINT (data));
+}
+
+static gpointer
+swfedit_u32_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits));
+}
+
+static void
+swfedit_rect_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_rect (out, data);
+}
+
+static gpointer
+swfedit_rect_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  SwfdecRect *rect = g_new (SwfdecRect, 1);
+  swfdec_bits_get_rect (bits, rect);
+  swfdec_bits_syncbits (bits);
+  return rect;
+}
+
+static void
+swfedit_string_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_string (out, data);
+}
+
+static gpointer
+swfedit_string_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  char *s;
+  s = swfdec_bits_get_string (bits, 7);
+  if (s == NULL)
+    s = g_strdup ("");
+  return s;
+}
+
+static void
+swfedit_rgb_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_rgb (out, GPOINTER_TO_UINT (data));
+}
+
+static gpointer
+swfedit_rgb_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER (swfdec_bits_get_color (bits));
+}
+
+static void
+swfedit_rgba_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_rgba (out, GPOINTER_TO_UINT (data));
+}
+
+static gpointer
+swfedit_rgba_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER (swfdec_bits_get_rgba (bits));
+}
+
+static void
+swfedit_matrix_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_matrix (out, data);
+}
+
+static gpointer
+swfedit_matrix_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  cairo_matrix_t *matrix = g_new (cairo_matrix_t, 1);
+
+  swfdec_bits_get_matrix (bits, matrix, NULL);
+  swfdec_bits_syncbits (bits);
+  return matrix;
+}
+
+static void
+swfedit_ctrans_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_color_transform (out, data);
+}
+
+static gpointer
+swfedit_ctrans_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  SwfdecColorTransform *ctrans = g_new (SwfdecColorTransform, 1);
+
+  swfdec_bits_get_color_transform (bits, ctrans);
+  swfdec_bits_syncbits (bits);
+  return ctrans;
+}
+
+static void
+swfedit_script_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  SwfdecScript *script = data;
+
+  swfdec_out_put_buffer (out, script->buffer);
+}
+
+static gpointer
+swfedit_script_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  while (token->parent)
+    token = token->parent;
+  if (!SWFEDIT_IS_FILE (token))
+    return NULL;
+  return swfdec_script_new_from_bits (bits, "original script", swfedit_file_get_version (SWFEDIT_FILE (token)));
+}
+
+static void
+swfedit_clipeventflags_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  while (token->parent)
+    token = token->parent;
+  g_assert (SWFEDIT_IS_FILE (token));
+  if (swfedit_file_get_version (SWFEDIT_FILE (token)) >= 6)
+    swfdec_out_put_u32 (out, GPOINTER_TO_UINT (data));
+  else
+    swfdec_out_put_u16 (out, GPOINTER_TO_UINT (data));
+}
+
+static gpointer
+swfedit_clipeventflags_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
+{
+  while (token->parent)
+    token = token->parent;
+  g_assert (SWFEDIT_IS_FILE (token));
+  if (swfedit_file_get_version (SWFEDIT_FILE (token)) >= 6)
+    return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits));
+  else
+    return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits));
+}
+
+struct {
+  void		(* write)	(SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint);
+  gpointer	(* read)	(SwfeditToken *token, SwfdecBits *bits, gconstpointer hint);
+} operations[SWFEDIT_N_TOKENS] = {
+  { swfedit_object_write, swfedit_object_read },
+  { swfedit_binary_write, swfedit_binary_read },
+  { swfedit_bit_write, swfedit_bit_read },
+  { swfedit_u8_write, swfedit_u8_read },
+  { swfedit_u16_write, swfedit_u16_read },
+  { swfedit_u32_write, swfedit_u32_read },
+  { swfedit_string_write, swfedit_string_read },
+  { swfedit_rect_write, swfedit_rect_read },
+  { swfedit_rgb_write, swfedit_rgb_read },
+  { swfedit_rgba_write, swfedit_rgba_read },
+  { swfedit_matrix_write, swfedit_matrix_read },
+  { swfedit_ctrans_write, swfedit_ctrans_read },
+  { swfedit_script_write, swfedit_script_read },
+  { swfedit_clipeventflags_write, swfedit_clipeventflags_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 (token, entry->value, out, NULL);
+}
+
+SwfdecBuffer *
+swfedit_tag_write (SwfeditToken *token)
+{
+  guint i;
+  SwfdecOut *out;
+
+  g_return_val_if_fail (SWFEDIT_IS_TOKEN (token), NULL);
+
+  out = swfdec_out_open ();
+  for (i = 0; i < token->tokens->len; i++) {
+    SwfeditTokenEntry *entry = &g_array_index (token->tokens, 
+	SwfeditTokenEntry, i);
+    if (entry->visible)
+      swfedit_tag_write_token (token, out, i);
+  }
+  return swfdec_out_close (out);
+}
+
+void
+swfedit_tag_read_token (SwfeditToken *token, SwfdecBits *bits,
+    const char *name, SwfeditTokenType type, gconstpointer hint)
+{
+  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 (token, bits, hint);
+  swfedit_token_add (token, name, type, data);
+}
+
+/*** TAGS ***/
+
+static const SwfeditTagDefinition ShowFrame[] = { { NULL, 0, 0, NULL } };
+static const SwfeditTagDefinition SetBackgroundColor[] = { { "color", SWFEDIT_TOKEN_RGB, 0, NULL }, { NULL, 0, 0, NULL } };
+static const SwfeditTagDefinition PlaceObject2Action[] = {
+  { "flags", SWFEDIT_TOKEN_CLIPEVENTFLAGS, 0, NULL },
+  { "size", SWFEDIT_TOKEN_UINT32, 0, NULL },
+  //{ "key code", SWFEDIT_TOKEN_UINT8, 0, NULL }, /* only if flag foo is set */
+  { "script", SWFEDIT_TOKEN_SCRIPT, 2, NULL },
+  { NULL, 0, 0, NULL }
+};
+static const SwfeditTagDefinition PlaceObject2[] = { 
+  { "has clip actions", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "has clip depth", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "has name", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "has ratio", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "has color transform", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "has matrix", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "has character", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "move", SWFEDIT_TOKEN_BIT, 0, NULL }, 
+  { "depth", SWFEDIT_TOKEN_UINT16, 0, NULL }, 
+  { "character", SWFEDIT_TOKEN_UINT16, 7, NULL }, 
+  { "matrix", SWFEDIT_TOKEN_MATRIX, 6, NULL }, 
+  { "color transform", SWFEDIT_TOKEN_CTRANS, 5, NULL }, 
+  { "ratio", SWFEDIT_TOKEN_UINT16, 4, NULL }, 
+  { "name", SWFEDIT_TOKEN_STRING, 3, NULL }, 
+  { "clip depth", SWFEDIT_TOKEN_UINT16, 2, NULL }, 
+  { "reserved", SWFEDIT_TOKEN_UINT16, 1, NULL },
+  { "all flags", SWFEDIT_TOKEN_CLIPEVENTFLAGS, 1, NULL },
+  { "actions", SWFEDIT_TOKEN_OBJECT, 1, PlaceObject2Action },
+  { NULL, 0, 0, NULL }
+};
+static const SwfeditTagDefinition DoAction[] = {
+  { "action", SWFEDIT_TOKEN_SCRIPT, 0, NULL },
+  { NULL, 0, 0, NULL }
+};
+static const SwfeditTagDefinition DoInitAction[] = {
+  { "character", SWFEDIT_TOKEN_UINT16, 0, NULL },
+  { "action", SWFEDIT_TOKEN_SCRIPT, 0, NULL },
+  { NULL, 0, 0, NULL }
+};
+
+static const SwfeditTagDefinition *tags[] = {
+  [SWFDEC_TAG_SHOWFRAME] = ShowFrame,
+  [SWFDEC_TAG_SETBACKGROUNDCOLOR] = SetBackgroundColor,
+  [SWFDEC_TAG_PLACEOBJECT2] = PlaceObject2,
+  [SWFDEC_TAG_DOACTION] = DoAction,
+  [SWFDEC_TAG_DOINITACTION] = DoInitAction,
+};
+
+static const SwfeditTagDefinition *
+swfedit_tag_get_definition (guint tag)
+{
+  if (tag >= G_N_ELEMENTS (tags))
+    return NULL;
+  return tags[tag];
+}
+
+/*** SWFEDIT_TAG ***/
+
+G_DEFINE_TYPE (SwfeditTag, swfedit_tag, SWFEDIT_TYPE_TOKEN)
+
+static void
+swfedit_tag_dispose (GObject *object)
+{
+  //SwfeditTag *tag = SWFEDIT_TAG (object);
+
+  G_OBJECT_CLASS (swfedit_tag_parent_class)->dispose (object);
+}
+
+static void
+swfedit_tag_changed (SwfeditToken *token, guint i)
+{
+  guint j;
+  SwfeditTag *tag = SWFEDIT_TAG (token);
+  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+  const SwfeditTagDefinition *def = swfedit_tag_get_definition (tag->tag);
+
+  if (def == NULL)
+    return;
+
+  for (j = i + 1; def[j].name; j++) {
+    if (def[j].n_items == i + 1) {
+      swfedit_token_set_visible (token, j, entry->value != NULL);
+    }
+  }
+  if (def[i].n_items != 0) {
+    entry = &g_array_index (token->tokens, 
+	SwfeditTokenEntry, def[i].n_items - 1);
+    if (entry->type == SWFEDIT_TOKEN_UINT32) {
+      SwfdecOut *out = swfdec_out_open ();
+      SwfdecBuffer *buffer;
+      swfedit_tag_write_token (token, out, def[i].n_items - 1);
+      buffer = swfdec_out_close (out);
+      if (entry->value != GUINT_TO_POINTER (buffer->length)) {
+	swfedit_token_set (token, def[i].n_items - 1, 
+	    GUINT_TO_POINTER (buffer->length));
+      }
+      swfdec_buffer_unref (buffer);
+    }
+  }
+}
+
+static void
+swfedit_tag_class_init (SwfeditTagClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  SwfeditTokenClass *token_class = SWFEDIT_TOKEN_CLASS (klass);
+
+  object_class->dispose = swfedit_tag_dispose;
+
+  token_class->changed = swfedit_tag_changed;
+}
+
+static void
+swfedit_tag_init (SwfeditTag *tag)
+{
+}
+
+void
+swfedit_tag_add_token (SwfeditToken *token, const char *name, SwfeditTokenType type,
+    gconstpointer hint)
+{
+  gpointer data;
+
+  if (type == SWFEDIT_TOKEN_OBJECT) {
+    data = swfedit_list_new (hint);
+    SWFEDIT_TOKEN (data)->parent = token;
+  } else {
+    data = swfedit_token_new_token (type);
+  }
+  swfedit_token_add (token, name, type, data);
+}
+
+void
+swfedit_tag_read_tag (SwfeditToken *token, SwfdecBits *bits, 
+    const SwfeditTagDefinition *def)
+{
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (bits != NULL);
+  g_return_if_fail (def != NULL);
+
+  if (def->n_items != 0) {
+    SwfeditTokenEntry *entry = &g_array_index (token->tokens, 
+	SwfeditTokenEntry, def->n_items - 1);
+    if (GPOINTER_TO_UINT (entry->value) == 0) {
+      swfedit_tag_add_token (token, def->name, def->type, def->hint);
+      swfedit_token_set_visible (token, token->tokens->len - 1, FALSE);
+    } else if (entry->type == SWFEDIT_TOKEN_BIT) {
+      swfedit_tag_read_token (token, bits, def->name, def->type, def->hint);
+    } else {
+      guint length = GPOINTER_TO_UINT (entry->value);
+      SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, length);
+      if (buffer == NULL) {
+	swfedit_tag_add_token (token, def->name, def->type, def->hint);
+      } else {
+	SwfdecBits bits2;
+	swfdec_bits_init (&bits2, buffer);
+	swfedit_tag_read_token (token, &bits2, def->name, def->type, def->hint);
+	swfdec_buffer_unref (buffer);
+      }
+    }
+  } else {
+    swfedit_tag_read_token (token, bits, def->name, def->type, def->hint);
+  }
+}
+
+SwfeditTag *
+swfedit_tag_new (SwfeditToken *parent, guint tag, SwfdecBuffer *buffer)
+{
+  SwfeditTag *item;
+  const SwfeditTagDefinition *def;
+
+  g_return_val_if_fail (SWFEDIT_IS_TOKEN (parent), NULL);
+
+  item = g_object_new (SWFEDIT_TYPE_TAG, NULL);
+  item->tag = tag;
+  SWFEDIT_TOKEN (item)->parent = parent;
+  def = swfedit_tag_get_definition (tag);
+  if (def) {
+    SwfdecBits bits;
+    swfdec_bits_init (&bits, buffer);
+    for (;def->name != NULL; def++) {
+      swfedit_tag_read_tag (SWFEDIT_TOKEN (item), &bits, def);
+    }
+    if (swfdec_bits_left (&bits)) {
+      SWFDEC_WARNING ("%u bytes %u bits left unparsed", 
+	  swfdec_bits_left (&bits) / 8, swfdec_bits_left (&bits) % 8);
+    }
+  } else {
+    swfedit_token_add (SWFEDIT_TOKEN (item), "contents", SWFEDIT_TOKEN_BINARY, buffer);
+  }
+  return item;
+}
+
diff --git a/tools/swfedit_tag.h b/tools/swfedit_tag.h
new file mode 100644
index 0000000..2f1d231
--- /dev/null
+++ b/tools/swfedit_tag.h
@@ -0,0 +1,83 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_TAG_H__
+#define __SWFEDIT_TAG_H__
+
+#include <libswfdec/swfdec_buffer.h>
+#include <libswfdec/swfdec_bits.h>
+#include "swfdec_out.h"
+#include "swfedit_token.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SwfeditTag SwfeditTag;
+typedef struct _SwfeditTagClass SwfeditTagClass;
+typedef struct _SwfeditTagDefinition SwfeditTagDefinition;
+
+struct _SwfeditTagDefinition {
+  const char *	  	name;			/* name to use for this field */
+  SwfeditTokenType     	type;			/* type of this field */
+  guint			n_items;		/* 1-indexed field to look at for item count (or 0 to use 1 item) */
+  gconstpointer		hint;			/* hint to pass to field when creating */
+};
+
+#define SWFEDIT_TYPE_TAG                    (swfedit_tag_get_type())
+#define SWFEDIT_IS_TAG(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TAG))
+#define SWFEDIT_IS_TAG_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TAG))
+#define SWFEDIT_TAG(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TAG, SwfeditTag))
+#define SWFEDIT_TAG_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TAG, SwfeditTagClass))
+#define SWFEDIT_TAG_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TAG, SwfeditTagClass))
+
+struct _SwfeditTag {
+  SwfeditToken		token;
+
+  guint			tag;		/* tag type */
+};
+
+struct _SwfeditTagClass {
+  SwfeditTokenClass	token_class;
+};
+
+GType		swfedit_tag_get_type	(void);
+
+SwfeditTag *	swfedit_tag_new		(SwfeditToken *		parent,
+					 guint			tag,
+					 SwfdecBuffer *		buffer);
+
+SwfdecBuffer *	swfedit_tag_write	(SwfeditToken *		token);
+void		swfedit_tag_write_token	(SwfeditToken *		token,
+					 SwfdecOut *		out,
+					 guint			i);
+void		swfedit_tag_add_token	(SwfeditToken *		token,
+					 const char *		name,
+					 SwfeditTokenType	type,
+					 gconstpointer		hint);
+void		swfedit_tag_read_token	(SwfeditToken *		token, 
+					 SwfdecBits *		bits,
+					 const char *		name,
+					 SwfeditTokenType	type,
+					 gconstpointer		hint);
+void		swfedit_tag_read_tag	(SwfeditToken *		token,
+					 SwfdecBits *		bits, 
+					 const SwfeditTagDefinition *def);
+
+G_END_DECLS
+
+#endif
diff --git a/tools/swfedit_token.c b/tools/swfedit_token.c
new file mode 100644
index 0000000..34496df
--- /dev/null
+++ b/tools/swfedit_token.c
@@ -0,0 +1,797 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, to_string to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <libswfdec/swfdec_buffer.h>
+#include <libswfdec/swfdec_color.h>
+#include <libswfdec/swfdec_script_internal.h>
+#include "swfedit_token.h"
+
+/*** CONVERTERS ***/
+
+static gboolean
+swfedit_parse_hex (const char *s, guint *result)
+{
+  guint byte;
+
+  if (s[0] >= '0' && s[0] <= '9')
+    byte = s[0] - '0';
+  else if (s[0] >= 'a' && s[0] <= 'f')
+    byte = s[0] + 10 - 'a';
+  else if (s[0] >= 'A' && s[0] <= 'F')
+    byte = s[0] + 10 - 'A';
+  else
+    return FALSE;
+  s++;
+  byte *= 16;
+  if (s[0] >= '0' && s[0] <= '9')
+    byte += s[0] - '0';
+  else if (s[0] >= 'a' && s[0] <= 'f')
+    byte += s[0] + 10 - 'a';
+  else if (s[0] >= 'A' && s[0] <= 'F')
+    byte += s[0] + 10 - 'A';
+  else
+    return FALSE;
+  *result = byte;
+  return TRUE;
+}
+
+static gpointer
+swfedit_binary_new (void)
+{
+  return swfdec_buffer_new ();
+}
+
+static gboolean
+swfedit_binary_from_string (const char *s, gpointer* result)
+{
+  GByteArray *array = g_byte_array_new ();
+  guint byte;
+  guint8 add;
+
+  while (g_ascii_isspace (*s)) s++;
+  do {
+    if (!swfedit_parse_hex (s, &byte))
+      break;
+    s += 2;
+    add = byte;
+    g_byte_array_append (array, &add, 1);
+    while (g_ascii_isspace (*s)) s++;
+  } while (*s != '\0');
+  if (*s == '\0') {
+    SwfdecBuffer *buffer = swfdec_buffer_new ();
+    buffer->length = array->len;
+    buffer->data = array->data;
+    g_byte_array_free (array, FALSE);
+    *result = buffer;
+    return TRUE;
+  }
+  g_byte_array_free (array, TRUE);
+  return FALSE;
+}
+
+static char *
+swfedit_binary_to_string (gconstpointer value)
+{
+  guint i;
+  const SwfdecBuffer *buffer = value;
+  GString *string = g_string_new ("");
+
+  for (i = 0; i < buffer->length; i++) {
+    if (i && i % 4 == 0)
+      g_string_append_c (string, ' ');
+    g_string_append_printf (string, "%02X", buffer->data[i]);
+  }
+  return g_string_free (string, FALSE);
+}
+
+static gboolean
+swfedit_bit_from_string (const char *s, gpointer* result)
+{
+  if (s[0] == '1' && s[1] == '\0')
+    *result = GUINT_TO_POINTER (1);
+  else if (s[0] == '0' && s[1] == '\0')
+    *result = GUINT_TO_POINTER (0);
+  else
+    return FALSE;
+  return TRUE;
+}
+
+static char *
+swfedit_bit_to_string (gconstpointer value)
+{
+  return g_strdup (value ? "1" : "0");
+}
+
+static gboolean
+swfedit_from_string_unsigned (const char *s, gulong max, gpointer* result)
+{
+  char *end;
+  gulong u;
+
+  g_assert (max <= G_MAXUINT);
+  u = strtoul (s, &end, 10);
+  if (*end != '\0')
+    return FALSE;
+  if (u > max)
+    return FALSE;
+  *result = GUINT_TO_POINTER (u);
+  return TRUE;
+}
+
+static gboolean
+swfedit_uint8_from_string (const char *s, gpointer* result)
+{
+  return swfedit_from_string_unsigned (s, G_MAXUINT8, result);
+}
+
+static gboolean
+swfedit_uint16_from_string (const char *s, gpointer* result)
+{
+  return swfedit_from_string_unsigned (s, G_MAXUINT16, result);
+}
+
+static gboolean
+swfedit_uint32_from_string (const char *s, gpointer* result)
+{
+  return swfedit_from_string_unsigned (s, G_MAXUINT32, result);
+}
+
+static char *
+swfedit_to_string_unsigned (gconstpointer value)
+{
+  return g_strdup_printf ("%u", GPOINTER_TO_UINT (value));
+}
+
+static char *
+swfedit_string_to_string (gconstpointer value)
+{
+  return g_strdup (value);
+}
+
+static gboolean
+swfedit_string_from_string (const char *s, gpointer* result)
+{
+  *result = g_strdup (s);
+  return TRUE;
+}
+
+static gpointer
+swfedit_rect_new (void)
+{
+  return g_new0 (SwfdecRect, 1);
+}
+
+static gboolean
+swfedit_rect_from_string (const char *s, gpointer* result)
+{
+  return FALSE;
+}
+
+static char *
+swfedit_rect_to_string (gconstpointer value)
+{
+  const SwfdecRect *rect = value;
+
+  return g_strdup_printf ("%d, %d, %d, %d", (int) rect->x0, (int) rect->y0,
+      (int) rect->x1, (int) rect->y1);
+}
+
+static gboolean
+swfedit_rgb_from_string (const char *s, gpointer* result)
+{
+  guint r, g, b;
+  if (strlen (s) != 6)
+    return FALSE;
+  if (!swfedit_parse_hex (s, &r))
+    return FALSE;
+  s += 2;
+  if (!swfedit_parse_hex (s, &g))
+    return FALSE;
+  s += 2;
+  if (!swfedit_parse_hex (s, &b))
+    return FALSE;
+  *result = GUINT_TO_POINTER (SWFDEC_COLOR_COMBINE (r, g, b, 0xFF));
+  return TRUE;
+}
+
+static char *
+swfedit_rgb_to_string (gconstpointer value)
+{
+  guint c = GPOINTER_TO_UINT (value);
+
+  return g_strdup_printf ("%02X%02X%02X", SWFDEC_COLOR_R (c),
+      SWFDEC_COLOR_G (c), SWFDEC_COLOR_B (c));
+}
+
+static gboolean
+swfedit_rgba_from_string (const char *s, gpointer* result)
+{
+  guint r, g, b, a;
+  if (strlen (s) != 8)
+    return FALSE;
+  if (!swfedit_parse_hex (s, &a))
+    return FALSE;
+  s += 2;
+  if (!swfedit_parse_hex (s, &r))
+    return FALSE;
+  s += 2;
+  if (!swfedit_parse_hex (s, &g))
+    return FALSE;
+  s += 2;
+  if (!swfedit_parse_hex (s, &b))
+    return FALSE;
+  *result = GUINT_TO_POINTER (SWFDEC_COLOR_COMBINE (r, g, b, a));
+  return TRUE;
+}
+
+static char *
+swfedit_rgba_to_string (gconstpointer value)
+{
+  guint c = GPOINTER_TO_UINT (value);
+
+  return g_strdup_printf ("%02X%02X%02X%02X", SWFDEC_COLOR_R (c),
+      SWFDEC_COLOR_G (c), SWFDEC_COLOR_B (c), SWFDEC_COLOR_A (c));
+}
+
+static gpointer
+swfedit_matrix_new (void)
+{
+  cairo_matrix_t *matrix = g_new (cairo_matrix_t, 1);
+
+  cairo_matrix_init_identity (matrix);
+  return matrix;
+}
+
+static gboolean
+swfedit_matrix_from_string (const char *s, gpointer* result)
+{
+  return FALSE;
+}
+
+static char *
+swfedit_matrix_to_string (gconstpointer value)
+{
+  const cairo_matrix_t *mat = value;
+
+  return g_strdup_printf ("{%g %g,  %g %g} + {%g, %g}", 
+      mat->xx, mat->xy, mat->yx, mat->yy, mat->x0, mat->y0);
+}
+
+static gpointer
+swfedit_ctrans_new (void)
+{
+  SwfdecColorTransform *trans = g_new (SwfdecColorTransform, 1);
+
+  swfdec_color_transform_init_identity (trans);
+  return trans;
+}
+
+static gboolean
+swfedit_ctrans_from_string (const char *s, gpointer* result)
+{
+  return FALSE;
+}
+
+static char *
+swfedit_ctrans_to_string (gconstpointer value)
+{
+  const SwfdecColorTransform *trans = value;
+
+  return g_strdup_printf ("{%d %d} {%d %d} {%d %d} {%d %d}", 
+      trans->ra, trans->rb, trans->ga, trans->gb, 
+      trans->ba, trans->bb, trans->aa, trans->ab);
+}
+
+static gpointer
+swfedit_script_new (void)
+{
+  return NULL;
+}
+
+static gboolean
+swfedit_script_from_string (const char *s, gpointer* result)
+{
+  gpointer buffer;
+  SwfdecScript *script;
+  
+  if (!swfedit_binary_from_string (s, &buffer)) {
+    return FALSE;
+  }
+
+  script = swfdec_script_new (buffer, "unknown", 6 /* FIXME */);
+  if (script != NULL) {
+    *result = script;
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+static char *
+swfedit_script_to_string (gconstpointer value)
+{
+  if (value == NULL)
+    return g_strdup ("");
+  else
+    return swfedit_binary_to_string (((SwfdecScript *) value)->buffer);
+}
+
+static void
+swfedit_script_free (gpointer script)
+{
+  if (script)
+    swfdec_script_unref (script);
+}
+
+struct {
+  gpointer	(* new)		(void);
+  gboolean	(* from_string)	(const char *s, gpointer *);
+  char *	(* to_string)	(gconstpointer value);
+  void	  	(* free)	(gpointer value);
+} converters[SWFEDIT_N_TOKENS] = {
+  { NULL, NULL, NULL, g_object_unref },
+  { swfedit_binary_new, swfedit_binary_from_string, swfedit_binary_to_string, (GDestroyNotify) swfdec_buffer_unref },
+  { NULL, swfedit_bit_from_string, swfedit_bit_to_string, NULL },
+  { NULL, swfedit_uint8_from_string, swfedit_to_string_unsigned, NULL },
+  { NULL, swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL },
+  { NULL, swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL },
+  { NULL, swfedit_string_from_string, swfedit_string_to_string, g_free },
+  { swfedit_rect_new, swfedit_rect_from_string, swfedit_rect_to_string, g_free },
+  { NULL, swfedit_rgb_from_string, swfedit_rgb_to_string, NULL },
+  { NULL, swfedit_rgba_from_string, swfedit_rgba_to_string, NULL },
+  { swfedit_matrix_new, swfedit_matrix_from_string, swfedit_matrix_to_string, g_free },
+  { swfedit_ctrans_new, swfedit_ctrans_from_string, swfedit_ctrans_to_string, g_free },
+  { swfedit_script_new, swfedit_script_from_string, swfedit_script_to_string, swfedit_script_free },
+  { NULL, swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL },
+};
+
+gpointer
+swfedit_token_new_token (SwfeditTokenType type)
+{
+  gpointer ret;
+
+  g_assert (type < G_N_ELEMENTS (converters));
+
+  if (!converters[type].new)
+    return NULL;
+  ret = converters[type].new ();
+  return ret;
+}
+
+/*** GTK_TREE_MODEL ***/
+
+#if 0
+#  define REPORT g_print ("%s\n", G_STRFUNC)
+#else
+#  define REPORT 
+#endif
+static GtkTreeModelFlags 
+swfedit_token_get_flags (GtkTreeModel *tree_model)
+{
+  REPORT;
+  return 0;
+}
+
+static gint
+swfedit_token_get_n_columns (GtkTreeModel *tree_model)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (tree_model);
+
+  REPORT;
+  return token->tokens->len;
+}
+
+static GType
+swfedit_token_get_column_type (GtkTreeModel *tree_model, gint index_)
+{
+  REPORT;
+  switch (index_) {
+    case SWFEDIT_COLUMN_NAME:
+      return G_TYPE_STRING;
+    case SWFEDIT_COLUMN_VALUE_VISIBLE:
+      return G_TYPE_BOOLEAN;
+    case SWFEDIT_COLUMN_VALUE_EDITABLE:
+      return G_TYPE_BOOLEAN;
+    case SWFEDIT_COLUMN_VALUE:
+      return G_TYPE_STRING;
+    default:
+      break;
+  }
+  g_assert_not_reached ();
+  return G_TYPE_NONE;
+}
+
+static gboolean
+swfedit_token_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (tree_model);
+  guint i = gtk_tree_path_get_indices (path)[0];
+  SwfeditTokenEntry *entry;
+  
+  REPORT;
+  if (i > token->tokens->len)
+    return FALSE;
+  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+  if (gtk_tree_path_get_depth (path) > 1) {
+    GtkTreePath *new;
+    int j;
+    int *indices;
+    gboolean ret;
+
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      return FALSE;
+    new = gtk_tree_path_new ();
+    indices = gtk_tree_path_get_indices (path);
+    for (j = 1; j < gtk_tree_path_get_depth (path); j++) {
+      gtk_tree_path_append_index (new, indices[j]);
+    }
+    ret = swfedit_token_get_iter (GTK_TREE_MODEL (entry->value), iter, new);
+    gtk_tree_path_free (new);
+    return ret;
+  } else {
+    iter->stamp = 0; /* FIXME */
+    iter->user_data = token;
+    iter->user_data2 = GINT_TO_POINTER (i);
+    return TRUE;
+  }
+}
+
+static GtkTreePath *
+swfedit_token_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data2), -1);
+
+  REPORT;
+  while (token->parent) {
+    guint i;
+    SwfeditToken *parent = token->parent;
+    for (i = 0; i < parent->tokens->len; i++) {
+      SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i);
+      if (entry->type != SWFEDIT_TOKEN_OBJECT)
+	continue;
+      if (entry->value == token)
+	break;
+    }
+    gtk_tree_path_prepend_index (path, i);
+    token = parent;
+  }
+  return path;
+}
+
+static void 
+swfedit_token_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter,
+    gint column, GValue *value)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2));
+
+  REPORT;
+  switch (column) {
+    case SWFEDIT_COLUMN_NAME:
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_string (value, entry->name);
+      return;
+    case SWFEDIT_COLUMN_VALUE_VISIBLE:
+      g_value_init (value, G_TYPE_BOOLEAN);
+      g_value_set_boolean (value, converters[entry->type].to_string != NULL);
+      return;
+    case SWFEDIT_COLUMN_VALUE_EDITABLE:
+      g_value_init (value, G_TYPE_BOOLEAN);
+      g_value_set_boolean (value, entry->visible);
+      return;
+    case SWFEDIT_COLUMN_VALUE:
+      g_value_init (value, G_TYPE_STRING);
+      if (converters[entry->type].to_string)
+	g_value_take_string (value, converters[entry->type].to_string (entry->value));
+      return;
+    default:
+      break;
+  }
+  g_assert_not_reached ();
+}
+
+static gboolean
+swfedit_token_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  int i;
+
+  REPORT;
+  i = GPOINTER_TO_INT (iter->user_data2) + 1;
+  if ((guint) i >= token->tokens->len)
+    return FALSE;
+
+  iter->user_data2 = GINT_TO_POINTER (i);
+  return TRUE;
+}
+
+static gboolean
+swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
+{
+  SwfeditToken *token;
+  SwfeditTokenEntry *entry;
+
+  REPORT;
+  if (parent) {
+    token = SWFEDIT_TOKEN (parent->user_data);
+    entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2));
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      return FALSE;
+    token = entry->value;
+  } else {
+    token = SWFEDIT_TOKEN (tree_model);
+  }
+  if (token->tokens->len == 0)
+    return FALSE;
+  iter->stamp = 0; /* FIXME */
+  iter->user_data = token;
+  iter->user_data2 = GINT_TO_POINTER (0);
+  return TRUE;
+}
+
+static gboolean
+swfedit_token_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2));
+
+  REPORT;
+  return entry->type == SWFEDIT_TOKEN_OBJECT && SWFEDIT_TOKEN (entry->value)->tokens->len > 0;
+}
+
+static gint
+swfedit_token_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (iter->user_data2));
+
+  REPORT;
+  if (entry->type != SWFEDIT_TOKEN_OBJECT)
+    return 0;
+
+  token = entry->value;
+  return token->tokens->len;
+}
+
+static gboolean
+swfedit_token_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter,
+    GtkTreeIter *parent, gint n)
+{
+  SwfeditToken *token;
+  SwfeditTokenEntry *entry;
+
+  REPORT;
+  if (parent) {
+    token = SWFEDIT_TOKEN (parent->user_data);
+    entry = &g_array_index (token->tokens, SwfeditTokenEntry, GPOINTER_TO_INT (parent->user_data2));
+
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      return FALSE;
+
+    token = entry->value;
+  } else {
+    token = SWFEDIT_TOKEN (tree_model);
+  }
+  if ((guint) n >= token->tokens->len)
+    return FALSE;
+  iter->stamp = 0; /* FIXME */
+  iter->user_data = token;
+  iter->user_data2 = GINT_TO_POINTER (n);
+  return TRUE;
+}
+
+static gboolean
+swfedit_token_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
+{
+  guint i;
+  SwfeditToken *token = SWFEDIT_TOKEN (child->user_data);
+  SwfeditToken *parent = token->parent;
+
+  REPORT;
+  if (parent == NULL)
+    return FALSE;
+
+  for (i = 0; i < parent->tokens->len; i++) {
+    SwfeditTokenEntry *entry = &g_array_index (parent->tokens, SwfeditTokenEntry, i);
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      continue;
+    if (entry->value == token)
+      break;
+  }
+  iter->stamp = 0; /* FIXME */
+  iter->user_data = parent;
+  iter->user_data2 = GINT_TO_POINTER (i);
+  return TRUE;
+}
+
+static void
+swfedit_token_tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags = swfedit_token_get_flags;
+  iface->get_n_columns = swfedit_token_get_n_columns;
+  iface->get_column_type = swfedit_token_get_column_type;
+  iface->get_iter = swfedit_token_get_iter;
+  iface->get_path = swfedit_token_get_path;
+  iface->get_value = swfedit_token_get_value;
+  iface->iter_next = swfedit_token_iter_next;
+  iface->iter_children = swfedit_token_iter_children;
+  iface->iter_has_child = swfedit_token_iter_has_child;
+  iface->iter_n_children = swfedit_token_iter_n_children;
+  iface->iter_nth_child = swfedit_token_iter_nth_child;
+  iface->iter_parent = swfedit_token_iter_parent;
+}
+
+/*** SWFEDIT_TOKEN ***/
+
+G_DEFINE_TYPE_WITH_CODE (SwfeditToken, swfedit_token, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, swfedit_token_tree_model_init))
+
+static void
+swfedit_token_dispose (GObject *object)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (object);
+  guint i;
+
+  for (i = 0; i < token->tokens->len; i++) {
+    SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+    g_free (entry->name);
+    if (converters[entry->type].free)
+      converters[entry->type].free (entry->value);
+  }
+  g_array_free (token->tokens, TRUE);
+
+  G_OBJECT_CLASS (swfedit_token_parent_class)->dispose (object);
+}
+
+static void
+swfedit_token_class_init (SwfeditTokenClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = swfedit_token_dispose;
+}
+
+static void
+swfedit_token_init (SwfeditToken *token)
+{
+  token->tokens = g_array_new (FALSE, FALSE, sizeof (SwfeditTokenEntry));
+}
+
+SwfeditToken *
+swfedit_token_new (void)
+{
+  SwfeditToken *token;
+
+  token = g_object_new (SWFEDIT_TYPE_TOKEN, NULL);
+  return token;
+}
+
+void
+swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, 
+    gpointer value)
+{
+  SwfeditTokenEntry entry = { NULL, type, value, TRUE };
+
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (type < SWFEDIT_N_TOKENS);
+
+  g_assert (type != SWFEDIT_TOKEN_OBJECT || value != NULL);
+  entry.name = g_strdup (name);
+  g_array_append_val (token->tokens, entry);
+}
+
+void
+swfedit_token_set (SwfeditToken *token, guint i, gpointer value)
+{
+  SwfeditTokenClass *klass;
+  SwfeditTokenEntry *entry;
+  GtkTreePath *path;
+  SwfeditToken *model;
+  GtkTreeIter iter;
+
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (i < token->tokens->len);
+
+  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+  if (converters[entry->type].free != NULL)
+    converters[entry->type].free (entry->value);
+  entry->value = value;
+  klass = SWFEDIT_TOKEN_GET_CLASS (token);
+  if (klass->changed)
+    klass->changed (token, i);
+
+  model = token;
+  while (model->parent)
+    model = model->parent;
+  iter.user_data = token;
+  iter.user_data2 = GUINT_TO_POINTER (i);
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+  gtk_tree_path_free (path);
+}
+
+void
+swfedit_token_set_iter (SwfeditToken *token, GtkTreeIter *iter, const char *value)
+{
+  SwfeditTokenClass *klass;
+  GtkTreeModel *model;
+  SwfeditTokenEntry *entry;
+  guint i;
+  gpointer new;
+  GtkTreePath *path;
+
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (iter != NULL);
+  g_return_if_fail (value != NULL);
+
+  model = GTK_TREE_MODEL (token);
+  token = iter->user_data;
+  i = GPOINTER_TO_UINT (iter->user_data2);
+  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+  if (converters[entry->type].from_string == NULL)
+    return;
+  if (!converters[entry->type].from_string (value, &new))
+    return;
+  if (converters[entry->type].free != NULL)
+    converters[entry->type].free (entry->value);
+  entry->value = new;
+  klass = SWFEDIT_TOKEN_GET_CLASS (token);
+  if (klass->changed)
+    klass->changed (token, i);
+
+  path = gtk_tree_model_get_path (model, iter);
+  gtk_tree_model_row_changed (model, path, iter);
+  gtk_tree_path_free (path);
+}
+
+void
+swfedit_token_set_visible (SwfeditToken *token, guint i, gboolean visible)
+{
+  SwfeditTokenEntry *entry;
+  GtkTreeModel *model;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (i < token->tokens->len);
+
+  entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+  if (entry->visible == visible)
+    return;
+
+  entry->visible = visible;
+  iter.stamp = 0; /* FIXME */
+  iter.user_data = token;
+  iter.user_data2 = GINT_TO_POINTER (i);
+  while (token->parent) 
+    token = token->parent;
+  model = GTK_TREE_MODEL (token);
+  path = gtk_tree_model_get_path (model, &iter);
+  gtk_tree_model_row_changed (model, path, &iter);
+  gtk_tree_path_free (path);
+}
diff --git a/tools/swfedit_token.h b/tools/swfedit_token.h
new file mode 100644
index 0000000..448f4cb
--- /dev/null
+++ b/tools/swfedit_token.h
@@ -0,0 +1,109 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_TOKEN_H__
+#define __SWFEDIT_TOKEN_H__
+
+#include <gtk/gtk.h>
+#include <libswfdec/swfdec_rect.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  SWFEDIT_TOKEN_OBJECT,
+  SWFEDIT_TOKEN_BINARY,
+  SWFEDIT_TOKEN_BIT,
+  SWFEDIT_TOKEN_UINT8,
+  SWFEDIT_TOKEN_UINT16,
+  SWFEDIT_TOKEN_UINT32,
+  SWFEDIT_TOKEN_STRING,
+  SWFEDIT_TOKEN_RECT,
+  SWFEDIT_TOKEN_RGB,
+  SWFEDIT_TOKEN_RGBA,
+  SWFEDIT_TOKEN_MATRIX,
+  SWFEDIT_TOKEN_CTRANS,
+  SWFEDIT_TOKEN_SCRIPT,
+  SWFEDIT_TOKEN_CLIPEVENTFLAGS,
+  SWFEDIT_N_TOKENS
+} SwfeditTokenType;
+
+typedef enum {
+  SWFEDIT_COLUMN_NAME,
+  SWFEDIT_COLUMN_VALUE_VISIBLE,
+  SWFEDIT_COLUMN_VALUE,
+  SWFEDIT_COLUMN_VALUE_EDITABLE
+} SwfeditColumn;
+
+typedef struct _SwfeditTokenEntry SwfeditTokenEntry;
+
+typedef struct _SwfeditToken SwfeditToken;
+typedef struct _SwfeditTokenClass SwfeditTokenClass;
+
+#define SWFEDIT_TYPE_TOKEN                    (swfedit_token_get_type())
+#define SWFEDIT_IS_TOKEN(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TOKEN))
+#define SWFEDIT_IS_TOKEN_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TOKEN))
+#define SWFEDIT_TOKEN(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TOKEN, SwfeditToken))
+#define SWFEDIT_TOKEN_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass))
+#define SWFEDIT_TOKEN_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass))
+
+struct _SwfeditTokenEntry {
+  char *		name;
+  SwfeditTokenType	type;
+  gpointer		value;
+  gboolean		visible;
+};
+
+struct _SwfeditToken {
+  GObject		object;
+
+  SwfeditToken *	parent;		/* parent of this token or NULL */
+  gchar *		name;		/* name of token */
+  GArray *		tokens;		/* of SwfeditTokenEntry */
+};
+
+struct _SwfeditTokenClass {
+  GObjectClass		object_class;
+
+  void			(* changed)		(SwfeditToken *		token,
+						 guint			id);
+};
+
+GType		swfedit_token_get_type		(void);
+
+gpointer	swfedit_token_new_token		(SwfeditTokenType	type);
+
+SwfeditToken *	swfedit_token_new		(void);
+void		swfedit_token_add		(SwfeditToken *		token,
+						 const char *		name,
+						 SwfeditTokenType	type,
+						 gpointer		value);
+void		swfedit_token_set		(SwfeditToken *		token,
+						 guint			i,
+						 gpointer		value);
+void		swfedit_token_set_iter		(SwfeditToken *		token,
+						 GtkTreeIter *		iter,
+						 const char *		value);
+void		swfedit_token_set_visible	(SwfeditToken *		token,
+						 guint			i,
+						 gboolean		visible);
+
+
+G_END_DECLS
+
+#endif
diff --git a/tools/swfscript.c b/tools/swfscript.c
new file mode 100644
index 0000000..4e2a9e4
--- /dev/null
+++ b/tools/swfscript.c
@@ -0,0 +1,298 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include "libswfdec/swfdec_script_internal.h"
+#include "swfdec_out.h"
+#include "swfedit_file.h"
+
+/* the stuff we look for */
+guint *add_trace = NULL;
+
+typedef gboolean ( *SwfeditTokenForeachFunc) (SwfeditToken *token, guint idx, 
+    const char *name, SwfeditTokenType type, gconstpointer value, gpointer data);
+
+static gboolean
+swfedit_token_foreach (SwfeditToken *token, SwfeditTokenForeachFunc func, 
+    gpointer data)
+{
+  SwfeditTokenEntry *entry;
+  guint i;
+
+  g_return_val_if_fail (SWFEDIT_IS_TOKEN (token), FALSE);
+  g_return_val_if_fail (func != NULL, FALSE);
+
+  for (i = 0; i < token->tokens->len; i++) {
+    entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
+    if (!func (token, i, entry->name, entry->type, entry->value, data))
+      return FALSE;
+    if (entry->type == SWFEDIT_TOKEN_OBJECT) {
+      if (!swfedit_token_foreach (entry->value, func, data))
+	return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+typedef struct {
+  guint			offset;			/* offset in bytes from start of script */
+  guint			new_offset;		/* new offset in bytes from start of script */
+  guint			new_actions;		/* number of actions in new script */
+} Action;
+
+typedef struct {
+  SwfdecScript *	script;			/* the original script */
+  SwfdecOut *		out;			/* output for new script or NULL when buffer is set */
+  SwfdecBuffer *	buffer;			/* buffer containing new script or NULL while constructing */
+  GArray *		actions;		/* all actions in the script */
+} State;
+
+static gboolean
+action_in_array (guint *array, guint action)
+{
+  if (array == NULL)
+    return FALSE;
+  while (*array != 0) {
+    if (*array == action)
+      return TRUE;
+    array++;
+  }
+  return FALSE;
+}
+
+static guint
+lookup_offset (GArray *array, guint offset)
+{
+  guint i;
+  for (i = 0; i < array->len; i++) {
+    Action *action = &g_array_index (array, Action, i);
+    if (action->offset == offset)
+      return action->new_offset;
+  }
+  g_assert_not_reached ();
+  return 0;
+}
+
+static gboolean
+fixup_jumps_foreach (gconstpointer bytecode, guint action,
+        const guint8 *data, guint len, gpointer user_data)
+{
+  State *state = user_data;
+    
+  if (action == 0x99 || action == 0x9d) {
+    guint offset = (guint8 *) bytecode - state->script->buffer->data;
+    guint jump_offset = offset + 5 + GINT16_FROM_LE (*((gint16 *) data));
+    offset = lookup_offset (state->actions, offset);
+    jump_offset = lookup_offset (state->actions, jump_offset);
+    *((gint16 *) &state->buffer->data[offset + 3]) = 
+      GINT16_TO_LE (jump_offset - offset - 5);
+  }
+  if (action == 0x8a || action == 0x8d) {
+    Action *cur = NULL; /* silence gcc */
+    guint id = action == 0x8a ? 2 : 0;
+    guint i, count;
+    guint offset = (guint8 *) bytecode - state->script->buffer->data;
+    for (i = 0; i < state->actions->len; i++) {
+      cur = &g_array_index (state->actions, Action, i);
+      if (cur->offset == offset) {
+	offset = cur->new_offset;
+	break;
+      }
+    }
+    g_assert (i < state->actions->len);
+    i = data[id];
+    count = cur->new_actions - 1; /* FIXME: only works as long as we append actions */
+    while (i > 0) {
+      cur++;
+      count += cur->new_actions;
+      i--;
+    }
+    g_assert (count < 256);
+    state->buffer->data[offset + 3 + id] = count;
+  }
+  return TRUE;
+}
+
+static gboolean
+modify_script_foreach (gconstpointer bytecode, guint action,
+        const guint8 *data, guint len, gpointer user_data)
+{
+  Action next;
+  State *state = user_data;
+    
+  next.offset = (guint8 *) bytecode - state->script->buffer->data;
+  next.new_offset = swfdec_out_get_bits (state->out) / 8;
+  next.new_actions = 1;
+  swfdec_out_put_u8 (state->out, action);
+  if (action & 0x80) {
+    swfdec_out_put_u16 (state->out, len);
+    swfdec_out_put_data (state->out, data, len);
+  }
+  if (action_in_array (add_trace, action)) {
+    swfdec_out_put_u8 (state->out, 0x4c); /* PushDuplicate */
+    swfdec_out_put_u8 (state->out, 0x26); /* Trace */
+    next.new_actions += 2;
+  }
+  g_array_append_val (state->actions, next);
+  return TRUE;
+}
+
+static gboolean
+modify_file (SwfeditToken *token, guint idx, const char *name, 
+    SwfeditTokenType type, gconstpointer value, gpointer data)
+{
+  Action end;
+  SwfdecScript *script;
+  State state;
+
+  if (type != SWFEDIT_TOKEN_SCRIPT)
+    return TRUE;
+
+  state.script = (SwfdecScript *) value;
+  state.out = swfdec_out_open ();
+  state.buffer = NULL;
+  state.actions = g_array_new (FALSE, FALSE, sizeof (Action));
+  swfdec_script_foreach (state.script, modify_script_foreach, &state);
+  /* compute end offset */
+  end.offset = g_array_index (state.actions, Action, state.actions->len - 1).offset;
+  if (state.script->buffer->data[end.offset] & 0x80) {
+    end.offset += GUINT16_FROM_LE (*((guint16* ) &state.script->buffer->data[end.offset + 1])) + 3;
+  } else {
+    end.offset++;
+  }
+  end.new_offset = swfdec_out_get_bits (state.out) / 8;
+  end.new_actions = 0;
+  g_array_append_val (state.actions, end);
+#if 0
+  {
+    guint i;
+    for (i = 0; i < state.actions->len; i++) {
+      Action *action = &g_array_index (state.actions, Action, i);
+      g_print ("%u  %u => %u  (%u actions)\n", i, action->offset, 
+	  action->new_offset, action->new_actions);
+    }
+  }
+#endif
+  /* maybe append 0 byte */
+  if (end.offset + 1 == state.script->buffer->length) {
+    swfdec_out_put_u8 (state.out, 0);
+  } else {
+    g_assert (end.offset == state.script->buffer->length);
+  }
+  state.buffer = swfdec_out_close (state.out);
+  state.out = NULL;
+  swfdec_script_foreach (state.script, fixup_jumps_foreach, &state);
+  g_array_free (state.actions, TRUE);
+#if 0
+  g_print ("got a new script in %u bytes - old script was %u bytes\n", 
+      state.buffer->length, state.script->buffer->length);
+#endif
+  script = swfdec_script_new (state.buffer, state.script->name, state.script->version);
+  g_assert (script);
+  swfedit_token_set (token, idx, script);
+
+  return TRUE;
+}
+
+static guint *
+string_to_action_list (const char *list)
+{
+  char **actions = g_strsplit (list, ",", -1);
+  guint *ret;
+  guint i, len;
+
+  len = g_strv_length (actions);
+  ret = g_new (guint, len + 1);
+  ret[len] = 0;
+  for (i = 0; i < len; i++) {
+    ret[i] = swfdec_action_get_from_name (actions[i]);
+    if (ret[i] == 0) {
+      g_printerr ("No such action \"%s\"\n", actions[i]);
+      g_free (actions);
+      g_free (ret);
+      return NULL;
+    }
+  }
+  g_free (actions);
+  return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+  SwfeditFile *file;
+  GError *error = NULL;
+  char *add_trace_s = NULL;
+  GOptionEntry options[] = {
+    { "add-trace", 't', 0, G_OPTION_ARG_STRING, &add_trace_s, "list of actions to trace", "ACTION, ACTION" },
+    { NULL }
+  };
+  GOptionContext *ctx;
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, "options");
+  g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
+  g_option_context_parse (ctx, &argc, &argv, &error);
+  g_option_context_free (ctx);
+  if (error) {
+    g_printerr ("error parsing arguments: %s\n", error->message);
+    g_error_free (error);
+    return 1;
+  }
+
+  if (argc < 2) {
+    g_printerr ("Usage: %s FILENAME [OUTPUT-FILENAME]\n", argv[0]);
+    return 1;
+  }
+  if (add_trace_s) {
+    add_trace = string_to_action_list (add_trace_s);
+    g_free (add_trace_s);
+    if (add_trace == NULL)
+      return 1;
+  }
+  file = swfedit_file_new (argv[1], &error);
+  if (file == NULL) {
+    g_printerr ("error opening file %s: %s\n", argv[1], error->message);
+    g_error_free (error);
+    return 1;
+  }
+  if (!swfedit_token_foreach (SWFEDIT_TOKEN (file), modify_file, NULL)) {
+    g_printerr ("modifying file %s failed.\n", argv[1]);
+    g_object_unref (file);
+    return 1;
+  }
+  g_free (file->filename);
+  if (argc > 2) {
+    file->filename = g_strdup (argv[2]);
+  } else {
+    file->filename = g_strdup_printf ("%s.out.swf", argv[1]);
+  }
+  if (!swfedit_file_save (file, &error)) {
+    g_printerr ("Error saving file: %s\n", error->message);
+    g_error_free (error);
+  }
+  g_print ("saved modified file to %s\n", file->filename);
+  g_object_unref (file);
+  return 0;
+}
+
commit 82495a0102e01a1706933f10696daed163692a71
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 19:38:20 2008 +0100

    update types list
    
    That has been forgotten for a long time...

diff --git a/doc/swfdec.types b/doc/swfdec.types
index 9b70671..c89c6d5 100644
--- a/doc/swfdec.types
+++ b/doc/swfdec.types
@@ -1,9 +1,15 @@
 #include <libswfdec/swfdec.h>
 #include <libswfdec-gtk/swfdec-gtk.h>
 
-swfdec_player_get_type
+swfdec_as_context_get_type
+swfdec_as_object_get_type
+swfdec_as_frame_get_type
+swfdec_as_function_get_type
 swfdec_audio_get_type
 swfdec_loader_get_type
+swfdec_player_get_type
+swfdec_player_scripting_get_type
+swfdec_system_get_type
 swfdec_gtk_loader_get_type
 swfdec_gtk_player_get_type
 swfdec_gtk_widget_get_type
commit a9d0e147d2889ed8d4c26bdcfde68d63187cbd6c
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 19:09:30 2008 +0100

    add tracing support

diff --git a/test/test/swfdec_test_test.c b/test/test/swfdec_test_test.c
index 2739204..04c6402 100644
--- a/test/test/swfdec_test_test.c
+++ b/test/test/swfdec_test_test.c
@@ -21,12 +21,112 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "swfdec_test_test.h"
 #include "swfdec_test_function.h"
 
+static void
+swfdec_test_throw (SwfdecAsContext *cx, const char *message, ...)
+{
+  SwfdecAsValue val;
+
+  if (!swfdec_as_context_catch (cx, &val)) {
+    va_list varargs;
+    char *s;
+
+    va_start (varargs, message);
+    s = g_strdup_vprintf (message, varargs);
+    va_end (varargs);
+
+    /* FIXME: Throw a real object here? */
+    SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (cx, s));
+  }
+  swfdec_as_context_throw (cx, &val);
+}
+
 /*** trace capturing ***/
 
+static void
+swfdec_test_test_trace_stop (SwfdecTestTest *test)
+{
+  if (test->trace_filename == NULL)
+    return;
+
+  if (test->trace_buffer &&
+      test->trace_offset != test->trace_buffer->data + test->trace_buffer->length)
+    test->trace_failed = TRUE;
+
+  if (test->trace_failed) {
+    /* FIXME: produce a diff here */
+    swfdec_test_throw (SWFDEC_AS_OBJECT (test)->context, "invalid trace output");
+  }
+
+  if (test->trace_buffer) {
+    swfdec_buffer_unref (test->trace_buffer);
+    test->trace_buffer = NULL;
+  }
+  g_free (test->trace_filename);
+  test->trace_filename = NULL;
+}
+
+static void
+swfdec_test_test_trace_start (SwfdecTestTest *test, const char *filename)
+{
+  GError *error = NULL;
+
+  g_assert (test->trace_filename == NULL);
+
+  test->trace_filename = g_strdup (filename);
+  test->trace_buffer = swfdec_buffer_new_from_file (filename, &error);
+  if (test->trace_buffer == NULL) {
+    swfdec_test_throw (SWFDEC_AS_OBJECT (test)->context, "Could not start trace: %s", error->message);
+    g_error_free (error);
+    return;
+  }
+  test->trace_offset = test->trace_buffer->data;
+}
+
+static void
+swfdec_test_test_trace_cb (SwfdecPlayer *player, const char *message, SwfdecTestTest *test)
+{
+  gsize len;
+
+  if (test->trace_buffer == NULL || test->trace_failed)
+    return;
 
+  len = strlen (message);
+  if (len + 1 > test->trace_buffer->length - (test->trace_offset -test->trace_buffer->data)) {
+    test->trace_failed = TRUE;
+    return;
+  }
+  if (memcmp (message, test->trace_offset, len) != 0) {
+    test->trace_failed = TRUE;
+    return;
+  }
+  test->trace_offset += len;
+  if (test->trace_offset[0] != '\n') {
+    test->trace_failed = TRUE;
+    return;
+  }
+  test->trace_offset++;
+}
+
+SWFDEC_TEST_FUNCTION ("Test_trace", swfdec_test_test_trace, 0)
+void
+swfdec_test_test_trace (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
+    SwfdecAsValue *argv, SwfdecAsValue *retval)
+{
+  SwfdecTestTest *test;
+  const char *filename;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEST_TEST, &test, "|s", &filename);
+
+  swfdec_test_test_trace_stop (test);
+  if (filename[0] == '\0')
+    return;
+  swfdec_test_test_trace_start (test, filename);
+}
 
 /*** SWFDEC_TEST_TEST ***/
 
@@ -37,9 +137,13 @@ swfdec_test_test_dispose (GObject *object)
 {
   SwfdecTestTest *test = SWFDEC_TEST_TEST (object);
 
+  /* FIXME: this can throw, is that ok? */
+  swfdec_test_test_trace_stop (test);
+
   g_free (test->filename);
   test->filename = NULL;
   if (test->player) {
+    g_signal_handlers_disconnect_matched (test, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, test);
     g_object_unref (test->player);
     test->player = NULL;
   }
@@ -60,20 +164,6 @@ swfdec_test_test_init (SwfdecTestTest *this)
 {
 }
 
-#if 0
-static void
-swfdec_test_throw (SwfdecAsContext *cx, const char *error)
-{
-  SwfdecAsValue val;
-
-  if (!swfdec_as_context_catch (cx, &val)) {
-    /* FIXME: Throw a real object here? */
-    SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, error));
-  }
-  swfdec_as_context_throw (cx, &val);
-}
-#endif
-
 static void
 swfdec_test_test_fscommand (SwfdecPlayer *player, const char *command, 
     const char *para, SwfdecTestTest *test)
@@ -91,6 +181,7 @@ swfdec_test_test_ensure_player (SwfdecTestTest *test)
 
   test->player = swfdec_player_new_from_file (test->filename);
   g_signal_connect (test, "fscommand", G_CALLBACK (swfdec_test_test_fscommand), test);
+  g_signal_connect (test, "trace", G_CALLBACK (swfdec_test_test_trace_cb), test);
   return TRUE;
 }
 
@@ -98,6 +189,7 @@ static void
 swfdec_test_do_reset (SwfdecTestTest *test, const char *filename)
 {
   if (test->player) {
+    g_signal_handlers_disconnect_matched (test, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, test);
     g_object_unref (test->player);
     test->player = NULL;
   }
@@ -153,7 +245,7 @@ swfdec_test_test_new (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
 
   SWFDEC_AS_CHECK (SWFDEC_TYPE_TEST_TEST, &test, "|s", &filename);
 
-  swfdec_test_do_reset (test, filename);
+  swfdec_test_do_reset (test, filename[0] ? filename : NULL);
 }
 
 SWFDEC_TEST_FUNCTION ("Test_rate", swfdec_test_test_get_rate, 0)
diff --git a/test/test/swfdec_test_test.h b/test/test/swfdec_test_test.h
index 7172897..6218f31 100644
--- a/test/test/swfdec_test_test.h
+++ b/test/test/swfdec_test_test.h
@@ -42,6 +42,12 @@ struct _SwfdecTestTest
   char *		filename;	/* file the player should be loaded from */
   SwfdecPlayer *	player;		/* the player or %NULL if none */
   gboolean		player_quit;	/* the player has called fscommand:quit */
+
+  /* trace stuff */
+  char *		trace_filename;	/* file we're parsing */
+  SwfdecBuffer *	trace_buffer;	/* buffer containing the file */
+  guchar *		trace_offset;	/* how far we've parsed the trace data */
+  gboolean		trace_failed;	/* TRUE if the tacing failed */
 };
 
 struct _SwfdecTestTestClass
commit 58323f9f4d7764038f17767bffaa05f99d77b4cf
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 19:09:19 2008 +0100

    add some more functions

diff --git a/test/test/swfdec_test_initialize.as b/test/test/swfdec_test_initialize.as
index 03eab16..338fdf0 100644
--- a/test/test/swfdec_test_initialize.as
+++ b/test/test/swfdec_test_initialize.as
@@ -18,11 +18,17 @@
  */
 
 Test = Native.Test;
-Test.reset = Native.Test_reset;
 Test.prototype = {};
+Test.prototype.advance = Native.Test_advance;
+Test.prototype.reset = Native.Test_reset;
+Test.prototype.trace = Native.Test_trace;
 Test.prototype.addProperty ("rate", Native.Test_get_rate, null);
 
 print = function (s) {
   if (s)
     Native.print ("INFO: " + s);
 };
+error = function (s) {
+  if (s)
+    Native.print ("ERROR: " + s);
+};
diff --git a/test/test/swfdec_test_initialize.h b/test/test/swfdec_test_initialize.h
index ff3ef4f..a7dc1f4 100644
--- a/test/test/swfdec_test_initialize.h
+++ b/test/test/swfdec_test_initialize.h
@@ -2,20 +2,31 @@
 
 /* compiled from swfdec_test_initialize.as */
 static const unsigned char swfdec_test_initialize[] = {
-  0x88, 0x57, 0x00, 0x0B,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
-  0x00, 0x72, 0x65, 0x73,  0x65, 0x74, 0x00, 0x54,  0x65, 0x73, 0x74, 0x5F,  0x72, 0x65, 0x73, 0x65,
-  0x74, 0x00, 0x70, 0x72,  0x6F, 0x74, 0x6F, 0x74,  0x79, 0x70, 0x65, 0x00,  0x72, 0x61, 0x74, 0x65,
-  0x00, 0x54, 0x65, 0x73,  0x74, 0x5F, 0x67, 0x65,  0x74, 0x5F, 0x72, 0x61,  0x74, 0x65, 0x00, 0x61,
-  0x64, 0x64, 0x50, 0x72,  0x6F, 0x70, 0x65, 0x72,  0x74, 0x79, 0x00, 0x70,  0x72, 0x69, 0x6E, 0x74,
-  0x00, 0x73, 0x00, 0x49,  0x4E, 0x46, 0x4F, 0x3A,  0x20, 0x00, 0x96, 0x04,  0x00, 0x08, 0x00, 0x08,
-  0x01, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x00, 0x4E,  0x1D, 0x96, 0x02, 0x00,  0x08, 0x00, 0x1C, 0x96,
-  0x04, 0x00, 0x08, 0x02,  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x03,  0x4E, 0x4F, 0x96, 0x02,
-  0x00, 0x08, 0x00, 0x1C,  0x96, 0x07, 0x00, 0x08,  0x04, 0x07, 0x00, 0x00,  0x00, 0x00, 0x43, 0x4F,
-  0x96, 0x03, 0x00, 0x02,  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x06,  0x4E, 0x96, 0x09, 0x00,
-  0x08, 0x05, 0x07, 0x03,  0x00, 0x00, 0x00, 0x08,  0x00, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x04, 0x4E,
-  0x96, 0x02, 0x00, 0x08,  0x07, 0x52, 0x17, 0x96,  0x02, 0x00, 0x08, 0x08,  0x9B, 0x07, 0x00, 0x00,
-  0x01, 0x00, 0x73, 0x00,  0x27, 0x00, 0x96, 0x02,  0x00, 0x08, 0x09, 0x1C,  0x12, 0x9D, 0x02, 0x00,
-  0x1B, 0x00, 0x96, 0x04,  0x00, 0x08, 0x0A, 0x08,  0x09, 0x1C, 0x47, 0x96,  0x07, 0x00, 0x07, 0x01,
-  0x00, 0x00, 0x00, 0x08,  0x01, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x08, 0x52,  0x17, 0x1D, 0x00
+  0x88, 0x8B, 0x00, 0x11,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
+  0x00, 0x70, 0x72, 0x6F,  0x74, 0x6F, 0x74, 0x79,  0x70, 0x65, 0x00, 0x61,  0x64, 0x76, 0x61, 0x6E,
+  0x63, 0x65, 0x00, 0x54,  0x65, 0x73, 0x74, 0x5F,  0x61, 0x64, 0x76, 0x61,  0x6E, 0x63, 0x65, 0x00,
+  0x72, 0x65, 0x73, 0x65,  0x74, 0x00, 0x54, 0x65,  0x73, 0x74, 0x5F, 0x72,  0x65, 0x73, 0x65, 0x74,
+  0x00, 0x74, 0x72, 0x61,  0x63, 0x65, 0x00, 0x54,  0x65, 0x73, 0x74, 0x5F,  0x74, 0x72, 0x61, 0x63,
+  0x65, 0x00, 0x72, 0x61,  0x74, 0x65, 0x00, 0x54,  0x65, 0x73, 0x74, 0x5F,  0x67, 0x65, 0x74, 0x5F,
+  0x72, 0x61, 0x74, 0x65,  0x00, 0x61, 0x64, 0x64,  0x50, 0x72, 0x6F, 0x70,  0x65, 0x72, 0x74, 0x79,
+  0x00, 0x70, 0x72, 0x69,  0x6E, 0x74, 0x00, 0x73,  0x00, 0x49, 0x4E, 0x46,  0x4F, 0x3A, 0x20, 0x00,
+  0x65, 0x72, 0x72, 0x6F,  0x72, 0x00, 0x45, 0x52,  0x52, 0x4F, 0x52, 0x3A,  0x20, 0x00, 0x96, 0x04,
+  0x00, 0x08, 0x00, 0x08,  0x01, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x00, 0x4E,  0x1D, 0x96, 0x02, 0x00,
+  0x08, 0x00, 0x1C, 0x96,  0x07, 0x00, 0x08, 0x02,  0x07, 0x00, 0x00, 0x00,  0x00, 0x43, 0x4F, 0x96,
+  0x02, 0x00, 0x08, 0x00,  0x1C, 0x96, 0x02, 0x00,  0x08, 0x02, 0x4E, 0x96,  0x04, 0x00, 0x08, 0x03,
+  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x04,  0x4E, 0x4F, 0x96, 0x02,  0x00, 0x08, 0x00, 0x1C,
+  0x96, 0x02, 0x00, 0x08,  0x02, 0x4E, 0x96, 0x04,  0x00, 0x08, 0x05, 0x08,  0x01, 0x1C, 0x96, 0x02,
+  0x00, 0x08, 0x06, 0x4E,  0x4F, 0x96, 0x02, 0x00,  0x08, 0x00, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x02,
+  0x4E, 0x96, 0x04, 0x00,  0x08, 0x07, 0x08, 0x01,  0x1C, 0x96, 0x02, 0x00,  0x08, 0x08, 0x4E, 0x4F,
+  0x96, 0x03, 0x00, 0x02,  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x0A,  0x4E, 0x96, 0x09, 0x00,
+  0x08, 0x09, 0x07, 0x03,  0x00, 0x00, 0x00, 0x08,  0x00, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x02, 0x4E,
+  0x96, 0x02, 0x00, 0x08,  0x0B, 0x52, 0x17, 0x96,  0x02, 0x00, 0x08, 0x0C,  0x9B, 0x07, 0x00, 0x00,
+  0x01, 0x00, 0x73, 0x00,  0x27, 0x00, 0x96, 0x02,  0x00, 0x08, 0x0D, 0x1C,  0x12, 0x9D, 0x02, 0x00,
+  0x1B, 0x00, 0x96, 0x04,  0x00, 0x08, 0x0E, 0x08,  0x0D, 0x1C, 0x47, 0x96,  0x07, 0x00, 0x07, 0x01,
+  0x00, 0x00, 0x00, 0x08,  0x01, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x0C, 0x52,  0x17, 0x1D, 0x96, 0x02,
+  0x00, 0x08, 0x0F, 0x9B,  0x07, 0x00, 0x00, 0x01,  0x00, 0x73, 0x00, 0x27,  0x00, 0x96, 0x02, 0x00,
+  0x08, 0x0D, 0x1C, 0x12,  0x9D, 0x02, 0x00, 0x1B,  0x00, 0x96, 0x04, 0x00,  0x08, 0x10, 0x08, 0x0D,
+  0x1C, 0x47, 0x96, 0x07,  0x00, 0x07, 0x01, 0x00,  0x00, 0x00, 0x08, 0x01,  0x1C, 0x96, 0x02, 0x00,
+  0x08, 0x0C, 0x52, 0x17,  0x1D, 0x00
 };
 
commit 7f948781726765ba56e96136b7ad8c65d34ad13d
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 19:06:28 2008 +0100

    compile script as version 8

diff --git a/test/test/compiler.c b/test/test/compiler.c
index ce0ef12..f4e0fcb 100644
--- a/test/test/compiler.c
+++ b/test/test/compiler.c
@@ -21,7 +21,7 @@ main (int argc, char **argv)
   SWFAction action;
   char *contents;
   GError *error = NULL;
-  gsize len;
+  int len;
   byte *data;
 
   if (argc != 3) {
@@ -38,7 +38,11 @@ main (int argc, char **argv)
     return 1;
   }
   action = newSWFAction (contents);
-  data = SWFAction_getByteCode (action, &len);
+  if (SWFAction_compile (action, 8, &len) != 0) {
+    g_printerr ("compilation failed\n");
+    return 1;
+  }
+  data = SWFAction_getByteCode (action, NULL);
   contents = g_malloc (len + sizeof (HEADER));
   memcpy (contents, HEADER, sizeof (HEADER));
   memcpy (contents + sizeof (HEADER), data, len);
commit b5e2671fbbcd142100dbaa22a735655b4a971267
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 18:30:43 2008 +0100

    This should be a pointer to a string here

diff --git a/test/test/swfdec_test_global.c b/test/test/swfdec_test_global.c
index 56c6317..6926944 100644
--- a/test/test/swfdec_test_global.c
+++ b/test/test/swfdec_test_global.c
@@ -33,7 +33,7 @@ swfdec_test_print (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
 {
   const char *s;
 
-  SWFDEC_AS_CHECK (0, NULL, "s", s);
+  SWFDEC_AS_CHECK (0, NULL, "s", &s);
 
   g_print ("%s\n", s);
 }
commit 93f761ed11e01b69e1793f9b9cbba6d45b82cee1
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 17:48:27 2008 +0100

    ignore autogenerated file

diff --git a/test/test/.gitignore b/test/test/.gitignore
index 7bd49f0..34dad19 100644
--- a/test/test/.gitignore
+++ b/test/test/.gitignore
@@ -1,2 +1,4 @@
+swfdec_test_function_list.h
+
 compiler
 test
commit 2d2654ba80b3fcc56c07f1364f0e5318c2605f25
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 17:47:35 2008 +0100

    add a test.rate property

diff --git a/test/test/swfdec_test_initialize.as b/test/test/swfdec_test_initialize.as
index 45d807b..03eab16 100644
--- a/test/test/swfdec_test_initialize.as
+++ b/test/test/swfdec_test_initialize.as
@@ -18,7 +18,9 @@
  */
 
 Test = Native.Test;
-Test.reset = Native.reset;
+Test.reset = Native.Test_reset;
+Test.prototype = {};
+Test.prototype.addProperty ("rate", Native.Test_get_rate, null);
 
 print = function (s) {
   if (s)
diff --git a/test/test/swfdec_test_initialize.h b/test/test/swfdec_test_initialize.h
index 547e492..ff3ef4f 100644
--- a/test/test/swfdec_test_initialize.h
+++ b/test/test/swfdec_test_initialize.h
@@ -2,14 +2,20 @@
 
 /* compiled from swfdec_test_initialize.as */
 static const unsigned char swfdec_test_initialize[] = {
-  0x88, 0x23, 0x00, 0x06,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
-  0x00, 0x72, 0x65, 0x73,  0x65, 0x74, 0x00, 0x70,  0x72, 0x69, 0x6E, 0x74,  0x00, 0x73, 0x00, 0x49,
-  0x4E, 0x46, 0x4F, 0x3A,  0x20, 0x00, 0x96, 0x04,  0x00, 0x08, 0x00, 0x08,  0x01, 0x1C, 0x96, 0x02,
-  0x00, 0x08, 0x00, 0x4E,  0x1D, 0x96, 0x02, 0x00,  0x08, 0x00, 0x1C, 0x96,  0x04, 0x00, 0x08, 0x02,
-  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x02,  0x4E, 0x4F, 0x96, 0x02,  0x00, 0x08, 0x03, 0x9B,
-  0x07, 0x00, 0x00, 0x01,  0x00, 0x73, 0x00, 0x27,  0x00, 0x96, 0x02, 0x00,  0x08, 0x04, 0x1C, 0x12,
-  0x9D, 0x02, 0x00, 0x1B,  0x00, 0x96, 0x04, 0x00,  0x08, 0x05, 0x08, 0x04,  0x1C, 0x47, 0x96, 0x07,
-  0x00, 0x07, 0x01, 0x00,  0x00, 0x00, 0x08, 0x01,  0x1C, 0x96, 0x02, 0x00,  0x08, 0x03, 0x52, 0x17,
-  0x1D, 0x00
+  0x88, 0x57, 0x00, 0x0B,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
+  0x00, 0x72, 0x65, 0x73,  0x65, 0x74, 0x00, 0x54,  0x65, 0x73, 0x74, 0x5F,  0x72, 0x65, 0x73, 0x65,
+  0x74, 0x00, 0x70, 0x72,  0x6F, 0x74, 0x6F, 0x74,  0x79, 0x70, 0x65, 0x00,  0x72, 0x61, 0x74, 0x65,
+  0x00, 0x54, 0x65, 0x73,  0x74, 0x5F, 0x67, 0x65,  0x74, 0x5F, 0x72, 0x61,  0x74, 0x65, 0x00, 0x61,
+  0x64, 0x64, 0x50, 0x72,  0x6F, 0x70, 0x65, 0x72,  0x74, 0x79, 0x00, 0x70,  0x72, 0x69, 0x6E, 0x74,
+  0x00, 0x73, 0x00, 0x49,  0x4E, 0x46, 0x4F, 0x3A,  0x20, 0x00, 0x96, 0x04,  0x00, 0x08, 0x00, 0x08,
+  0x01, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x00, 0x4E,  0x1D, 0x96, 0x02, 0x00,  0x08, 0x00, 0x1C, 0x96,
+  0x04, 0x00, 0x08, 0x02,  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x03,  0x4E, 0x4F, 0x96, 0x02,
+  0x00, 0x08, 0x00, 0x1C,  0x96, 0x07, 0x00, 0x08,  0x04, 0x07, 0x00, 0x00,  0x00, 0x00, 0x43, 0x4F,
+  0x96, 0x03, 0x00, 0x02,  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x06,  0x4E, 0x96, 0x09, 0x00,
+  0x08, 0x05, 0x07, 0x03,  0x00, 0x00, 0x00, 0x08,  0x00, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x04, 0x4E,
+  0x96, 0x02, 0x00, 0x08,  0x07, 0x52, 0x17, 0x96,  0x02, 0x00, 0x08, 0x08,  0x9B, 0x07, 0x00, 0x00,
+  0x01, 0x00, 0x73, 0x00,  0x27, 0x00, 0x96, 0x02,  0x00, 0x08, 0x09, 0x1C,  0x12, 0x9D, 0x02, 0x00,
+  0x1B, 0x00, 0x96, 0x04,  0x00, 0x08, 0x0A, 0x08,  0x09, 0x1C, 0x47, 0x96,  0x07, 0x00, 0x07, 0x01,
+  0x00, 0x00, 0x00, 0x08,  0x01, 0x1C, 0x96, 0x02,  0x00, 0x08, 0x08, 0x52,  0x17, 0x1D, 0x00
 };
 
diff --git a/test/test/swfdec_test_test.c b/test/test/swfdec_test_test.c
index 74473ee..2739204 100644
--- a/test/test/swfdec_test_test.c
+++ b/test/test/swfdec_test_test.c
@@ -155,3 +155,16 @@ swfdec_test_test_new (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
 
   swfdec_test_do_reset (test, filename);
 }
+
+SWFDEC_TEST_FUNCTION ("Test_rate", swfdec_test_test_get_rate, 0)
+void
+swfdec_test_test_get_rate (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
+    SwfdecAsValue *argv, SwfdecAsValue *retval)
+{
+  SwfdecTestTest *test;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEST_TEST, &test, "");
+
+  SWFDEC_AS_VALUE_SET_NUMBER (retval, test->player ? swfdec_player_get_rate (test->player) : 0);
+}
+
commit 9185793d14379606672581a282839a56ca53c31e
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 17:43:25 2008 +0100

    This file is autogenerated
    
    oops

diff --git a/test/test/swfdec_test_function_list.h b/test/test/swfdec_test_function_list.h
deleted file mode 100644
index 9ddf1c1..0000000
--- a/test/test/swfdec_test_function_list.h
+++ /dev/null
@@ -1,4 +0,0 @@
-SWFDEC_TEST_FUNCTION ("print", swfdec_test_print, 0)
-SWFDEC_TEST_FUNCTION ("Test_advance", swfdec_test_test_advance, 0)
-SWFDEC_TEST_FUNCTION ("Test_reset", swfdec_test_test_reset, 0)
-SWFDEC_TEST_FUNCTION ("Test", swfdec_test_test_new, swfdec_test_test_get_type)
commit 2ed69da82ede7d0ea800cbad4306e663a237078d
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 17:43:09 2008 +0100

    add a global print function

diff --git a/test/test/Makefile.am b/test/test/Makefile.am
index 6bc3dac..b610daa 100644
--- a/test/test/Makefile.am
+++ b/test/test/Makefile.am
@@ -5,6 +5,7 @@ swfdec_test_sources = \
 	swfdec_test.c \
 	swfdec_test_function.c \
 	swfdec_test_function.h \
+	swfdec_test_global.c \
 	swfdec_test_test.c \
 	swfdec_test_test.h
 
diff --git a/test/test/swfdec_test_function_list.h b/test/test/swfdec_test_function_list.h
index 46908ab..9ddf1c1 100644
--- a/test/test/swfdec_test_function_list.h
+++ b/test/test/swfdec_test_function_list.h
@@ -1,3 +1,4 @@
+SWFDEC_TEST_FUNCTION ("print", swfdec_test_print, 0)
 SWFDEC_TEST_FUNCTION ("Test_advance", swfdec_test_test_advance, 0)
 SWFDEC_TEST_FUNCTION ("Test_reset", swfdec_test_test_reset, 0)
 SWFDEC_TEST_FUNCTION ("Test", swfdec_test_test_new, swfdec_test_test_get_type)
diff --git a/test/test/swfdec_test_global.c b/test/test/swfdec_test_global.c
index 2eac05c..56c6317 100644
--- a/test/test/swfdec_test_global.c
+++ b/test/test/swfdec_test_global.c
@@ -26,4 +26,15 @@
 #include "swfdec_test_function.h"
 #include "swfdec_test_initialize.h"
 
+SWFDEC_TEST_FUNCTION ("print", swfdec_test_print, 0)
+void
+swfdec_test_print (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
+    SwfdecAsValue *argv, SwfdecAsValue *retval)
+{
+  const char *s;
+
+  SWFDEC_AS_CHECK (0, NULL, "s", s);
+
+  g_print ("%s\n", s);
+}
 
diff --git a/test/test/swfdec_test_initialize.as b/test/test/swfdec_test_initialize.as
index bc6e5ad..45d807b 100644
--- a/test/test/swfdec_test_initialize.as
+++ b/test/test/swfdec_test_initialize.as
@@ -18,3 +18,9 @@
  */
 
 Test = Native.Test;
+Test.reset = Native.reset;
+
+print = function (s) {
+  if (s)
+    Native.print ("INFO: " + s);
+};
diff --git a/test/test/swfdec_test_initialize.h b/test/test/swfdec_test_initialize.h
index ea1dfde..547e492 100644
--- a/test/test/swfdec_test_initialize.h
+++ b/test/test/swfdec_test_initialize.h
@@ -2,8 +2,14 @@
 
 /* compiled from swfdec_test_initialize.as */
 static const unsigned char swfdec_test_initialize[] = {
-  0x88, 0x0E, 0x00, 0x02,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
-  0x00, 0x96, 0x04, 0x00,  0x08, 0x00, 0x08, 0x01,  0x1C, 0x96, 0x02, 0x00,  0x08, 0x00, 0x4E, 0x1D,
-  0x00
+  0x88, 0x23, 0x00, 0x06,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
+  0x00, 0x72, 0x65, 0x73,  0x65, 0x74, 0x00, 0x70,  0x72, 0x69, 0x6E, 0x74,  0x00, 0x73, 0x00, 0x49,
+  0x4E, 0x46, 0x4F, 0x3A,  0x20, 0x00, 0x96, 0x04,  0x00, 0x08, 0x00, 0x08,  0x01, 0x1C, 0x96, 0x02,
+  0x00, 0x08, 0x00, 0x4E,  0x1D, 0x96, 0x02, 0x00,  0x08, 0x00, 0x1C, 0x96,  0x04, 0x00, 0x08, 0x02,
+  0x08, 0x01, 0x1C, 0x96,  0x02, 0x00, 0x08, 0x02,  0x4E, 0x4F, 0x96, 0x02,  0x00, 0x08, 0x03, 0x9B,
+  0x07, 0x00, 0x00, 0x01,  0x00, 0x73, 0x00, 0x27,  0x00, 0x96, 0x02, 0x00,  0x08, 0x04, 0x1C, 0x12,
+  0x9D, 0x02, 0x00, 0x1B,  0x00, 0x96, 0x04, 0x00,  0x08, 0x05, 0x08, 0x04,  0x1C, 0x47, 0x96, 0x07,
+  0x00, 0x07, 0x01, 0x00,  0x00, 0x00, 0x08, 0x01,  0x1C, 0x96, 0x02, 0x00,  0x08, 0x03, 0x52, 0x17,
+  0x1D, 0x00
 };
 
commit d72839e43e6766d1fd4636bf32417365b8eb76b6
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 17:38:08 2008 +0100

    add new scripted testsuite

diff --git a/configure.ac b/configure.ac
index c09d6cf..98d756a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -354,6 +354,7 @@ player/Makefile
 test/Makefile
 test/image/Makefile
 test/sound/Makefile
+test/test/Makefile
 test/trace/Makefile
 test/various/Makefile
 vivified/Makefile
diff --git a/test/Makefile.am b/test/Makefile.am
index 1aca7fa..d69a082 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = image sound trace various
+SUBDIRS = image sound test trace various
 
 
 if WITH_GTK
diff --git a/test/test/.gitignore b/test/test/.gitignore
new file mode 100644
index 0000000..7bd49f0
--- /dev/null
+++ b/test/test/.gitignore
@@ -0,0 +1,2 @@
+compiler
+test
diff --git a/test/test/Makefile.am b/test/test/Makefile.am
new file mode 100644
index 0000000..6bc3dac
--- /dev/null
+++ b/test/test/Makefile.am
@@ -0,0 +1,30 @@
+check_PROGRAMS = test
+TESTS = $(check_PROGRAMS)
+
+swfdec_test_sources = \
+	swfdec_test.c \
+	swfdec_test_function.c \
+	swfdec_test_function.h \
+	swfdec_test_test.c \
+	swfdec_test_test.h
+
+BUILT_SOURCES = \
+	swfdec_test_function_list.h
+
+CLEANFILES = \
+	$(BUILT_SOURCES)
+
+test_SOURCES = \
+	$(swfdec_test_sources) \
+	$(BUILT_SOURCES)
+
+test_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWFDEC_CFLAGS) $(CAIRO_CFLAGS)
+test_LDFLAGS = $(SWFDEC_LIBS) $(GTK_LIBS) $(CAIRO_LIBS)
+
+swfdec_test_function_list.h: $(swfdec_test_sources)
+	(cd $(srcdir) \
+	  && grep -he "^SWFDEC_TEST_FUNCTION" $(swfdec_test_sources) \
+	 ) >> xgen-sfl \
+	&& (cmp -s xgen-sfl swfdec_test_function_list.h || cp xgen-sfl swfdec_test_function_list.h) \
+	&& rm -f xgen-sfl
+
diff --git a/test/test/compiler.c b/test/test/compiler.c
new file mode 100644
index 0000000..ce0ef12
--- /dev/null
+++ b/test/test/compiler.c
@@ -0,0 +1,53 @@
+//gcc -Wall -Werror `pkg-config --libs --cflags libming glib-2.0` compiler.c -o compiler
+
+#include <glib.h>
+#include <ming.h>
+#include <string.h>
+
+/* This is what is used to compile the Actionscript parts of the source to
+ * Swfdec test scripts that can later be executed.
+ * Note that this is pretty much a hack until someone writes a proper
+ * Actionscript compiler for Swfdec.
+ * Also note that the creation of the include-scripts should probably not be 
+ * autorun, as we don't want to depend on external bugs in Ming, only on internal ones.
+ */
+
+/* header to put in front of script */
+#define HEADER "Swfdec Test Script\0\1"
+
+int
+main (int argc, char **argv)
+{
+  SWFAction action;
+  char *contents;
+  GError *error = NULL;
+  gsize len;
+  byte *data;
+
+  if (argc != 3) {
+    g_print ("usage: %s INFILE OUTFILE\n\n", argv[0]);
+    return 1;
+  }
+
+  Ming_init ();
+
+  if (!g_file_get_contents (argv[1], &contents, NULL, &error)) {
+    g_printerr ("%s\n", error->message);
+    g_error_free (error);
+    error = NULL;
+    return 1;
+  }
+  action = newSWFAction (contents);
+  data = SWFAction_getByteCode (action, &len);
+  contents = g_malloc (len + sizeof (HEADER));
+  memcpy (contents, HEADER, sizeof (HEADER));
+  memcpy (contents + sizeof (HEADER), data, len);
+  if (!g_file_set_contents (argv[2], contents, len + sizeof (HEADER), &error)) {
+    g_printerr ("%s\n", error->message);
+    g_error_free (error);
+    error = NULL;
+    return 1;
+  }
+  g_free (contents);
+  return 0;
+}
diff --git a/test/test/swfdec_test.c b/test/test/swfdec_test.c
new file mode 100644
index 0000000..1e65276
--- /dev/null
+++ b/test/test/swfdec_test.c
@@ -0,0 +1,141 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libswfdec/swfdec.h>
+/* FIXME: no internal headers please */
+#include <libswfdec/swfdec_as_array.h>
+#include <libswfdec/swfdec_as_internal.h>
+
+#include "swfdec_test_function.h"
+#include "swfdec_test_initialize.h"
+
+
+/* Start of script file */
+#define SWFDEC_TEST_FILE_ID "Swfdec Test Script\0\1"
+/* Flash version the script engine runs in */
+#define SWFDEC_TEST_VERSION 8
+
+static SwfdecScript *
+load_script (const char *filename)
+{
+  SwfdecBuffer *file, *buffer;
+  SwfdecScript *script;
+  GError *error = NULL;
+
+  if (filename == NULL)
+    filename = "default.sts";
+
+  file = swfdec_buffer_new_from_file (filename, &error);
+  if (file == NULL) {
+    g_print ("ERROR: %s\n", error->message);
+    g_error_free (error);
+    return NULL;
+  }
+  if (file->length < sizeof (SWFDEC_TEST_FILE_ID) + 1 ||
+      memcmp (file->data, SWFDEC_TEST_FILE_ID, sizeof (SWFDEC_TEST_FILE_ID) != 0)) {
+    g_print ("ERROR: %s is not a Swfdec test script\n", filename);
+    swfdec_buffer_unref (file);
+    return NULL;
+  }
+  buffer = swfdec_buffer_new_subbuffer (file, sizeof (SWFDEC_TEST_FILE_ID), 
+      file->length - sizeof (SWFDEC_TEST_FILE_ID));
+  swfdec_buffer_unref (file);
+  script = swfdec_script_new (buffer, "main", SWFDEC_TEST_VERSION);
+  return script;
+}
+
+int
+main (int argc, char **argv)
+{
+  char *script_filename = NULL;
+  GError *error = NULL;
+  SwfdecAsContext *context;
+  SwfdecAsObject *array;
+  SwfdecScript *script;
+  SwfdecAsValue val;
+  int i, ret;
+
+  GOptionEntry options[] = {
+    { "script", 's', 0, G_OPTION_ARG_STRING, &script_filename, "script to execute if not ./default.sts", "FILENAME" },
+    { NULL }
+  };
+  GOptionContext *ctx;
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, "options");
+  g_option_context_parse (ctx, &argc, &argv, &error);
+  g_option_context_free (ctx);
+
+  if (error) {
+    g_printerr ("ERROR: wrong command line arguments: %s\n", error->message);
+    g_error_free (error);
+    return EXIT_FAILURE;
+  }
+
+  if (argc < 2) {
+    g_printerr ("ERROR: Usage: %s [OPTIONS] filename\n", argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  swfdec_init ();
+  script = load_script (script_filename);
+  g_free (script_filename);
+  if (script == NULL)
+    return EXIT_FAILURE;
+
+  context = g_object_new (SWFDEC_TYPE_AS_CONTEXT, NULL);
+  swfdec_as_context_startup (context, SWFDEC_TEST_VERSION);
+  swfdec_test_function_init_context (context);
+  swfdec_as_context_run_init_script (context, swfdec_test_initialize, 
+      sizeof (swfdec_test_initialize), SWFDEC_TEST_VERSION);
+
+  array = swfdec_as_array_new (context);
+  if (array == NULL) {
+    g_print ("ERROR: Not enough memory");
+    return EXIT_FAILURE;
+  }
+  for (i = 1; i < argc; i++) {
+    SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (context, argv[i]));
+    swfdec_as_array_push (SWFDEC_AS_ARRAY (array), &val);
+  }
+  SWFDEC_AS_VALUE_SET_OBJECT (&val, array);
+  swfdec_as_object_set_variable (context->global, 
+    swfdec_as_context_get_string (context, "filenames"), &val);
+  swfdec_as_object_run (context->global, script);
+  if (swfdec_as_context_catch (context, &val)) {
+    g_print ("ERROR: %s\n", swfdec_as_value_to_string (context, &val));
+    ret = EXIT_FAILURE;
+  } else {
+    g_print ("SUCCESS\n");
+    ret = EXIT_SUCCESS;
+  }
+
+  swfdec_script_unref (script);
+  g_object_unref (context);
+
+  return ret;
+}
+
diff --git a/test/test/swfdec_test_function.c b/test/test/swfdec_test_function.c
new file mode 100644
index 0000000..0109582
--- /dev/null
+++ b/test/test/swfdec_test_function.c
@@ -0,0 +1,67 @@
+/* SwfdecTestfied
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_test_function.h"
+#include "swfdec_test_function_list.h"
+
+/* needed by the function list */
+#include "swfdec_test_test.h"
+
+
+/* include swfdec_test_function_list with special macro definition, so we get a nice
+ * way to initialize it */
+#undef SWFDEC_TEST_FUNCTION
+#define SWFDEC_TEST_FUNCTION(name, fun, type) \
+  { name, fun, type },
+static const struct {
+  const char *		name;
+  SwfdecAsNative	fun;
+  GType			(* type) (void);
+} functions[] = {
+#include "swfdec_test_function_list.h"
+  { NULL, NULL, NULL }
+};
+#undef SWFDEC_TEST_FUNCTION
+
+void
+swfdec_test_function_init_context (SwfdecAsContext *cx)
+{ 
+  SwfdecAsObject *obj;
+  SwfdecAsValue val;
+  guint i;
+
+  obj = swfdec_as_object_new (cx);
+  if (obj == NULL)
+    return;
+  SWFDEC_AS_VALUE_SET_OBJECT (&val, obj);
+  swfdec_as_object_set_variable (cx->global, 
+      swfdec_as_context_get_string (cx, "Native"), &val);
+
+  for (i = 0; functions[i].name; i++) {
+    GType type = functions[i].type ? functions[i].type () : 0;
+    swfdec_as_object_add_constructor (obj,
+      swfdec_as_context_get_string (cx, functions[i].name),
+      type, type, functions[i].fun, 0, NULL);
+  }
+}
+
diff --git a/test/test/swfdec_test_function.h b/test/test/swfdec_test_function.h
new file mode 100644
index 0000000..08b6c27
--- /dev/null
+++ b/test/test/swfdec_test_function.h
@@ -0,0 +1,35 @@
+/* SwfdecTestfied
+ * 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
+ */
+
+#include <libswfdec/swfdec.h>
+
+#ifndef _SWFDEC_TEST_FUNCTION_H_
+#define _SWFDEC_TEST_FUNCTION_H_
+
+G_BEGIN_DECLS
+
+
+#define SWFDEC_TEST_FUNCTION(name, fun, type) \
+  void fun (SwfdecAsContext *cx, SwfdecAsObject *this, guint argc, SwfdecAsValue *argv, SwfdecAsValue *retval);
+
+void		swfdec_test_function_init_context	(SwfdecAsContext *cx);
+
+
+G_END_DECLS
+#endif
diff --git a/test/test/swfdec_test_function_list.h b/test/test/swfdec_test_function_list.h
new file mode 100644
index 0000000..46908ab
--- /dev/null
+++ b/test/test/swfdec_test_function_list.h
@@ -0,0 +1,3 @@
+SWFDEC_TEST_FUNCTION ("Test_advance", swfdec_test_test_advance, 0)
+SWFDEC_TEST_FUNCTION ("Test_reset", swfdec_test_test_reset, 0)
+SWFDEC_TEST_FUNCTION ("Test", swfdec_test_test_new, swfdec_test_test_get_type)
diff --git a/test/test/swfdec_test_global.c b/test/test/swfdec_test_global.c
new file mode 100644
index 0000000..2eac05c
--- /dev/null
+++ b/test/test/swfdec_test_global.c
@@ -0,0 +1,29 @@
+/* Swfdec
+ * Copyright (C) 2008 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 <libswfdec/swfdec.h>
+
+#include "swfdec_test_function.h"
+#include "swfdec_test_initialize.h"
+
+
diff --git a/test/test/swfdec_test_initialize.as b/test/test/swfdec_test_initialize.as
new file mode 100644
index 0000000..bc6e5ad
--- /dev/null
+++ b/test/test/swfdec_test_initialize.as
@@ -0,0 +1,20 @@
+/* Swfdec
+ * Copyright (C) 2008 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
+ */
+
+Test = Native.Test;
diff --git a/test/test/swfdec_test_initialize.h b/test/test/swfdec_test_initialize.h
new file mode 100644
index 0000000..ea1dfde
--- /dev/null
+++ b/test/test/swfdec_test_initialize.h
@@ -0,0 +1,9 @@
+/* This file is autogenerated, do not edit! */
+
+/* compiled from swfdec_test_initialize.as */
+static const unsigned char swfdec_test_initialize[] = {
+  0x88, 0x0E, 0x00, 0x02,  0x00, 0x54, 0x65, 0x73,  0x74, 0x00, 0x4E, 0x61,  0x74, 0x69, 0x76, 0x65,
+  0x00, 0x96, 0x04, 0x00,  0x08, 0x00, 0x08, 0x01,  0x1C, 0x96, 0x02, 0x00,  0x08, 0x00, 0x4E, 0x1D,
+  0x00
+};
+
diff --git a/test/test/swfdec_test_test.c b/test/test/swfdec_test_test.c
new file mode 100644
index 0000000..74473ee
--- /dev/null
+++ b/test/test/swfdec_test_test.c
@@ -0,0 +1,157 @@
+/* Swfdec
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "swfdec_test_test.h"
+#include "swfdec_test_function.h"
+
+/*** trace capturing ***/
+
+
+
+/*** SWFDEC_TEST_TEST ***/
+
+G_DEFINE_TYPE (SwfdecTestTest, swfdec_test_test, SWFDEC_TYPE_AS_OBJECT)
+
+static void
+swfdec_test_test_dispose (GObject *object)
+{
+  SwfdecTestTest *test = SWFDEC_TEST_TEST (object);
+
+  g_free (test->filename);
+  test->filename = NULL;
+  if (test->player) {
+    g_object_unref (test->player);
+    test->player = NULL;
+  }
+
+  G_OBJECT_CLASS (swfdec_test_test_parent_class)->dispose (object);
+}
+
+static void
+swfdec_test_test_class_init (SwfdecTestTestClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = swfdec_test_test_dispose;
+}
+
+static void
+swfdec_test_test_init (SwfdecTestTest *this)
+{
+}
+
+#if 0
+static void
+swfdec_test_throw (SwfdecAsContext *cx, const char *error)
+{
+  SwfdecAsValue val;
+
+  if (!swfdec_as_context_catch (cx, &val)) {
+    /* FIXME: Throw a real object here? */
+    SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_get_string (cx, error));
+  }
+  swfdec_as_context_throw (cx, &val);
+}
+#endif
+
+static void
+swfdec_test_test_fscommand (SwfdecPlayer *player, const char *command, 
+    const char *para, SwfdecTestTest *test)
+{
+  if (g_ascii_strcasecmp (command, "quit")) {
+    test->player_quit = TRUE;
+  }
+}
+
+static gboolean
+swfdec_test_test_ensure_player (SwfdecTestTest *test)
+{
+  if (test->filename == NULL)
+    return FALSE;
+
+  test->player = swfdec_player_new_from_file (test->filename);
+  g_signal_connect (test, "fscommand", G_CALLBACK (swfdec_test_test_fscommand), test);
+  return TRUE;
+}
+
+static void
+swfdec_test_do_reset (SwfdecTestTest *test, const char *filename)
+{
+  if (test->player) {
+    g_object_unref (test->player);
+    test->player = NULL;
+  }
+  if (filename == NULL)
+    return;
+
+  test->filename = g_strdup (filename);
+}
+
+SWFDEC_TEST_FUNCTION ("Test_advance", swfdec_test_test_advance, 0)
+void
+swfdec_test_test_advance (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
+    SwfdecAsValue *argv, SwfdecAsValue *retval)
+{
+  SwfdecTestTest *test;
+  int msecs;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEST_TEST, &test, "i", &msecs);
+
+  if (msecs <= 0 || test->player_quit)
+    return;
+  swfdec_test_test_ensure_player (test);
+  while (msecs > 0 && !test->player_quit) {
+    int next_event = swfdec_player_get_next_event (test->player);
+    if (next_event < 0)
+      break;
+    next_event = MIN (next_event, msecs);
+    swfdec_player_advance (test->player, next_event);
+    msecs -= next_event;
+  }
+}
+
+SWFDEC_TEST_FUNCTION ("Test_reset", swfdec_test_test_reset, 0)
+void
+swfdec_test_test_reset (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
+    SwfdecAsValue *argv, SwfdecAsValue *retval)
+{
+  SwfdecTestTest *test;
+  const char *filename;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEST_TEST, &test, "|s", &filename);
+
+  swfdec_test_do_reset (test, filename);
+}
+
+SWFDEC_TEST_FUNCTION ("Test", swfdec_test_test_new, swfdec_test_test_get_type)
+void
+swfdec_test_test_new (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
+    SwfdecAsValue *argv, SwfdecAsValue *retval)
+{
+  SwfdecTestTest *test;
+  const char *filename;
+
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_TEST_TEST, &test, "|s", &filename);
+
+  swfdec_test_do_reset (test, filename);
+}
diff --git a/test/test/swfdec_test_test.h b/test/test/swfdec_test_test.h
new file mode 100644
index 0000000..7172897
--- /dev/null
+++ b/test/test/swfdec_test_test.h
@@ -0,0 +1,56 @@
+/* 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_TEST_TEST_H_
+#define _SWFDEC_TEST_TEST_H_
+
+#include <libswfdec/swfdec.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecTestTest SwfdecTestTest;
+typedef struct _SwfdecTestTestClass SwfdecTestTestClass;
+
+#define SWFDEC_TYPE_TEST_TEST                    (swfdec_test_test_get_type())
+#define SWFDEC_IS_TEST_TEST(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_TEST_TEST))
+#define SWFDEC_IS_TEST_TEST_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_TEST_TEST))
+#define SWFDEC_TEST_TEST(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_TEST_TEST, SwfdecTestTest))
+#define SWFDEC_TEST_TEST_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_TEST_TEST, SwfdecTestTestClass))
+#define SWFDEC_TEST_TEST_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_TEST_TEST, SwfdecTestTestClass))
+
+struct _SwfdecTestTest
+{
+  SwfdecAsObject	as_object;
+
+  char *		filename;	/* file the player should be loaded from */
+  SwfdecPlayer *	player;		/* the player or %NULL if none */
+  gboolean		player_quit;	/* the player has called fscommand:quit */
+};
+
+struct _SwfdecTestTestClass
+{
+  SwfdecAsObjectClass	as_object_class;
+};
+
+GType		swfdec_test_test_get_type	(void);
+
+
+G_END_DECLS
+#endif
commit 97d89d8dc0605f5d42c4bf56039822c22e2eaaa8
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 7 17:20:52 2008 +0100

    fix typo

diff --git a/vivified/core/Makefile.am b/vivified/core/Makefile.am
index 1252f5a..5e274f1 100644
--- a/vivified/core/Makefile.am
+++ b/vivified/core/Makefile.am
@@ -50,7 +50,7 @@ vivi_function_list.h: $(libvivified_core_source)
 	(cd $(srcdir) \
 	  && grep -he "^VIVI_FUNCTION" $(libvivified_core_sources) \
 	 ) >> xgen-vfl \
-	&& (cmp -s xgen-vfl vivi_asnative.h || cp xgen-vfl vivi_function_list.h) \
+	&& (cmp -s xgen-vfl vivi_function_list.h || cp xgen-vfl vivi_function_list.h) \
 	&& rm -f xgen-vfl
 
 vivi_marshal.h: vivi_marshal.list Makefile


More information about the Swfdec mailing list