[Swfdec] 9 commits - libswfdec/js libswfdec/swfdec_bits.c libswfdec/swfdec_bits.h libswfdec/swfdec_codec_screen.c libswfdec/swfdec_image.c libswfdec/swfdec_script.c test/Makefile.am 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

Benjamin Otte company at kemper.freedesktop.org
Tue Feb 13 12:15:46 PST 2007


 libswfdec/js/jsinterp.c         |    1 
 libswfdec/swfdec_bits.c         |  108 +++++++++++++
 libswfdec/swfdec_bits.h         |    4 
 libswfdec/swfdec_codec_screen.c |   68 +-------
 libswfdec/swfdec_image.c        |  107 ++++++-------
 libswfdec/swfdec_script.c       |   40 +++++
 test/Makefile.am                |   11 +
 test/swfdec_out.c               |  119 +++++++++++++++
 test/swfdec_out.h               |   67 ++++----
 test/swfedit.c                  |   19 +-
 test/swfedit_file.c             |   18 +-
 test/swfedit_file.h             |    1 
 test/swfedit_list.c             |  133 +++++++++++++++++
 test/swfedit_list.h             |   61 +++++++
 test/swfedit_tag.c              |  311 +++++++++++++++++++++++++++++++++++-----
 test/swfedit_tag.h              |   21 ++
 test/swfedit_token.c            |  211 +++++++++++++++++++++++++--
 test/swfedit_token.h            |   18 ++
 18 files changed, 1105 insertions(+), 213 deletions(-)

New commits:
diff-tree 634736d7d5ba5b7e3ef43893278b95fac05a3cb2 (from b3f04131da03829352ae315b2986ecda634c58c9)
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Feb 13 21:15:37 2007 +0100

    swf may be used uninitialized in this function

diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c
index 910087a..ab095f6 100644
--- a/libswfdec/js/jsinterp.c
+++ b/libswfdec/js/jsinterp.c
@@ -807,6 +807,7 @@ js_Invoke(JSContext *cx, uintN argc, uin
         }
         fun = NULL;
         script = NULL;
+	swf = NULL;
         minargs = nvars = 0;
 
         /* Try a call or construct native object op. */
diff-tree b3f04131da03829352ae315b2986ecda634c58c9 (from 319fb2b1931124bc32607519c26c50d7318236a4)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 12 20:25:57 2007 +0100

    add a libswfedit, so I can use this editing code for more tools

diff --git a/test/Makefile.am b/test/Makefile.am
index 0d1dd19..b55bf0f 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,5 +1,7 @@
 SUBDIRS = image sound trace various
 
+noinst_LTLIBRARIES = libswfedit.la
+
 if WITH_GTK
 noinst_PROGRAMS = swfdec-extract dump parse swfedit
 else
@@ -15,12 +17,15 @@ parse_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS
 swfdec_extract_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
 swfdec_extract_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS)
 
+libswfedit_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(GTK_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
+libswfedit_la_LDFLAGS = $(SWF_LIBS) $(GTK_LIBS)
+
 swfedit_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(GTK_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
 swfedit_LDFLAGS = $(SWF_LIBS) $(GTK_LIBS)
+swfedit_LDADD = libswfedit.la
 
-swfedit_SOURCES = \
+libswfedit_la_SOURCES = \
 	swfdec_out.c \
-	swfedit.c \
 	swfedit_file.c \
 	swfedit_list.c \
 	swfedit_tag.c \
diff-tree 319fb2b1931124bc32607519c26c50d7318236a4 (from 9b0b34f65f692da1da2aea559c74926fa610420b)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 12 19:37:55 2007 +0100

    more work in making swfedit useful

diff --git a/test/swfedit_file.c b/test/swfedit_file.c
index 165cde7..26699de 100644
--- a/test/swfedit_file.c
+++ b/test/swfedit_file.c
@@ -284,3 +284,14 @@ swfedit_file_save (SwfeditFile *file, GE
   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
index e904950..ecd096a 100644
--- a/test/swfedit_file.h
+++ b/test/swfedit_file.h
@@ -52,6 +52,7 @@ SwfeditFile *	swfedit_file_new		(const c
 
 gboolean	swfedit_file_save		(SwfeditFile *	file,
 						 GError **	error);
+guint		swfedit_file_get_version	(SwfeditFile *	file);
 
 
 G_END_DECLS
diff --git a/test/swfedit_list.c b/test/swfedit_list.c
index 35ab0a3..289d7de 100644
--- a/test/swfedit_list.c
+++ b/test/swfedit_list.c
@@ -99,7 +99,7 @@ swfedit_list_new (const SwfeditTagDefini
 }
 
 SwfeditList *
-swfedit_list_new_read (SwfdecBits *bits, const SwfeditTagDefinition *def)
+swfedit_list_new_read (SwfeditToken *parent, SwfdecBits *bits, const SwfeditTagDefinition *def)
 {
   SwfeditList *list;
   SwfeditTokenEntry *entry;
@@ -109,6 +109,7 @@ swfedit_list_new_read (SwfdecBits *bits,
   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;
@@ -120,7 +121,10 @@ swfedit_list_new_read (SwfdecBits *bits,
 
     def++;
     for (;def->name != NULL; def++) {
-      swfedit_tag_read_tag (SWFEDIT_TOKEN (list), bits, 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;
   }
diff --git a/test/swfedit_list.h b/test/swfedit_list.h
index d51ae73..e0666f7 100644
--- a/test/swfedit_list.h
+++ b/test/swfedit_list.h
@@ -49,7 +49,8 @@ struct _SwfeditListClass {
 GType		swfedit_list_get_type	(void);
 
 SwfeditList *	swfedit_list_new	(const SwfeditTagDefinition *	def);
-SwfeditList *	swfedit_list_new_read	(SwfdecBits *			bits,
+SwfeditList *	swfedit_list_new_read	(SwfeditToken *			parent,
+					 SwfdecBits *			bits,
 					 const SwfeditTagDefinition *	def);
 
 SwfdecBuffer *	swfedit_list_write	(SwfeditList *			list);
diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c
index c8cf442..75137a5 100644
--- a/test/swfedit_tag.c
+++ b/test/swfedit_tag.c
@@ -30,12 +30,13 @@
 #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 (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_object_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   SwfdecBuffer *buffer;
 
@@ -46,19 +47,19 @@ swfedit_object_write (gpointer data, Swf
 }
 
 static gpointer
-swfedit_object_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_object_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
-  return swfedit_list_new_read (bits, hint);
+  return swfedit_list_new_read (token, bits, hint);
 }
 
 static void
-swfedit_binary_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_binary_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_buffer (out, data);
 }
 
 static gpointer
-swfedit_binary_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_binary_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, -1);
   if (buffer == NULL)
@@ -67,61 +68,61 @@ swfedit_binary_read (SwfdecBits *bits, g
 }
 
 static void
-swfedit_bit_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_bit_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_bit (out, data ? TRUE : FALSE);
 }
 
 static gpointer
-swfedit_bit_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_bit_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_getbit (bits) ? 1 : 0);
 }
 
 static void
-swfedit_u8_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+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 (SwfdecBits *bits, gconstpointer hint)
+swfedit_u8_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_u8 (bits));
 }
 
 static void
-swfedit_u16_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+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 (SwfdecBits *bits, gconstpointer hint)
+swfedit_u16_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits));
 }
 
 static void
-swfedit_u32_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+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 (SwfdecBits *bits, gconstpointer hint)
+swfedit_u32_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits));
 }
 
 static void
-swfedit_rect_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_rect_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_rect (out, data);
 }
 
 static gpointer
-swfedit_rect_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_rect_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   SwfdecRect *rect = g_new (SwfdecRect, 1);
   swfdec_bits_get_rect (bits, rect);
@@ -130,13 +131,13 @@ swfedit_rect_read (SwfdecBits *bits, gco
 }
 
 static void
-swfedit_string_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_string_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_string (out, data);
 }
 
 static gpointer
-swfedit_string_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_string_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   char *s;
   s = swfdec_bits_get_string (bits);
@@ -146,37 +147,37 @@ swfedit_string_read (SwfdecBits *bits, g
 }
 
 static void
-swfedit_rgb_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+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 (SwfdecBits *bits, gconstpointer hint)
+swfedit_rgb_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_color (bits));
 }
 
 static void
-swfedit_rgba_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+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 (SwfdecBits *bits, gconstpointer hint)
+swfedit_rgba_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_rgba (bits));
 }
 
 static void
-swfedit_matrix_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_matrix_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_matrix (out, data);
 }
 
 static gpointer
-swfedit_matrix_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_matrix_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   cairo_matrix_t *matrix = g_new (cairo_matrix_t, 1);
 
@@ -186,13 +187,13 @@ swfedit_matrix_read (SwfdecBits *bits, g
 }
 
 static void
-swfedit_ctrans_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_ctrans_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_color_transform (out, data);
 }
 
 static gpointer
-swfedit_ctrans_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_ctrans_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
   SwfdecColorTransform *ctrans = g_new (SwfdecColorTransform, 1);
 
@@ -202,7 +203,7 @@ swfedit_ctrans_read (SwfdecBits *bits, g
 }
 
 static void
-swfedit_script_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+swfedit_script_write (SwfeditToken *token, gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   SwfdecScript *script = data;
 
@@ -210,14 +211,42 @@ swfedit_script_write (gpointer data, Swf
 }
 
 static gpointer
-swfedit_script_read (SwfdecBits *bits, gconstpointer hint)
+swfedit_script_read (SwfeditToken *token, SwfdecBits *bits, gconstpointer hint)
 {
-  return swfdec_script_new (bits, "original script", 6 /* FIXME */);
+  while (token->parent)
+    token = token->parent;
+  if (!SWFEDIT_IS_FILE (token))
+    return NULL;
+  return swfdec_script_new (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)	(gpointer data, SwfdecOut *out, gconstpointer hint);
-  gpointer	(* read)	(SwfdecBits *bits, gconstpointer hint);
+  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 },
@@ -232,6 +261,7 @@ struct {
   { 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
@@ -245,7 +275,7 @@ swfedit_tag_write_token (SwfeditToken *t
   entry = &g_array_index (token->tokens, 
       SwfeditTokenEntry, i);
   g_assert (operations[entry->type].write != NULL);
-  operations[entry->type].write (entry->value, out, NULL);
+  operations[entry->type].write (token, entry->value, out, NULL);
 }
 
 SwfdecBuffer *
@@ -276,9 +306,7 @@ swfedit_tag_read_token (SwfeditToken *to
   g_return_if_fail (name != NULL);
   
   g_assert (operations[type].read != NULL);
-  data = operations[type].read (bits, hint);
-  if (type == SWFEDIT_TOKEN_OBJECT)
-    SWFEDIT_TOKEN (data)->parent = token;
+  data = operations[type].read (token, bits, hint);
   swfedit_token_add (token, name, type, data);
 }
 
@@ -287,11 +315,10 @@ swfedit_tag_read_token (SwfeditToken *to
 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_UINT32, 0, NULL },
-  { "reserved", SWFEDIT_TOKEN_UINT16, 0, NULL },
+  { "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, 3, NULL },
+  { "script", SWFEDIT_TOKEN_SCRIPT, 2, NULL },
   { NULL, 0, 0, NULL }
 };
 static const SwfeditTagDefinition PlaceObject2[] = { 
@@ -310,15 +337,27 @@ static const SwfeditTagDefinition PlaceO
   { "ratio", SWFEDIT_TOKEN_UINT16, 4, NULL }, 
   { "name", SWFEDIT_TOKEN_STRING, 3, NULL }, 
   { "clip depth", SWFEDIT_TOKEN_UINT16, 2, NULL }, 
-  { "all flags", SWFEDIT_TOKEN_UINT32, 1, 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 *
diff --git a/test/swfedit_token.c b/test/swfedit_token.c
index 9155b94..005e6c1 100644
--- a/test/swfedit_token.c
+++ b/test/swfedit_token.c
@@ -364,6 +364,7 @@ struct {
   { 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
diff --git a/test/swfedit_token.h b/test/swfedit_token.h
index 53c3b62..c9e522f 100644
--- a/test/swfedit_token.h
+++ b/test/swfedit_token.h
@@ -39,6 +39,7 @@ typedef enum {
   SWFEDIT_TOKEN_MATRIX,
   SWFEDIT_TOKEN_CTRANS,
   SWFEDIT_TOKEN_SCRIPT,
+  SWFEDIT_TOKEN_CLIPEVENTFLAGS,
   SWFEDIT_N_TOKENS
 } SwfeditTokenType;
 
diff-tree 9b0b34f65f692da1da2aea559c74926fa610420b (from 4a5112ee3285fd9cf3ba55bece78c2110c40cace)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 12 15:56:46 2007 +0100

    Updates to swfedit - it now presents PlaceObject2 tags nicely

diff --git a/test/Makefile.am b/test/Makefile.am
index 00c8203..0d1dd19 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -22,11 +22,13 @@ swfedit_SOURCES = \
 	swfdec_out.c \
 	swfedit.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/swfdec_out.c b/test/swfdec_out.c
index 0719b0f..b17cedb 100644
--- a/test/swfdec_out.c
+++ b/test/swfdec_out.c
@@ -67,6 +67,14 @@ swfdec_out_close (SwfdecOut *out)
 }
 
 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);
@@ -186,6 +194,21 @@ swfdec_out_put_sbits (SwfdecOut *out, in
   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)
 {
@@ -202,12 +225,12 @@ static guint
 swfdec_out_sbits_required (int x)
 {
   if (x < 0)
-    x = -x;
+    x = !x;
   return swfdec_out_bits_required (x) + 1;
 }
 
 void
-swfdec_out_put_rect (SwfdecOut *out, SwfdecRect *rect)
+swfdec_out_put_rect (SwfdecOut *out, const SwfdecRect *rect)
 {
   int x0, x1, y0, y1;
   guint req, tmp;
@@ -236,6 +259,98 @@ swfdec_out_put_rect (SwfdecOut *out, Swf
 }
 
 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);
diff --git a/test/swfdec_out.h b/test/swfdec_out.h
index d1f916c..3a22f36 100644
--- a/test/swfdec_out.h
+++ b/test/swfdec_out.h
@@ -40,37 +40,44 @@ struct _SwfdecOut {
 #define SWFDEC_OUT_STEP (32)
 
 SwfdecOut *	swfdec_out_open			(void);
-SwfdecBuffer *	swfdec_out_close		(SwfdecOut *	out);
+SwfdecBuffer *	swfdec_out_close		(SwfdecOut *		out);
 
-unsigned int	swfdec_out_left	  		(SwfdecOut *	out);
-void		swfdec_out_ensure_bits		(SwfdecOut *	out,
-						 unsigned int	bits);
-void		swfdec_out_prepare_bytes	(SwfdecOut *	out,
-						 unsigned int	bytes);
-
-void		swfdec_out_put_bit		(SwfdecOut *	out,
-						 gboolean	bit);
-void		swfdec_out_put_bits		(SwfdecOut *	out,
-						 guint		bits,
-						 guint		n_bits);
-void		swfdec_out_put_sbits		(SwfdecOut *	out,
-						 int		bits,
-						 guint		n_bits);
-void		swfdec_out_put_buffer		(SwfdecOut *	out,
-						 SwfdecBuffer *	buffer);
-void		swfdec_out_put_u8		(SwfdecOut *	out,
-						 guint		i);
-void		swfdec_out_put_u16		(SwfdecOut *	out,
-						 guint		i);
-void		swfdec_out_put_u32		(SwfdecOut *	out,
-						 guint		i);
-
-void		swfdec_out_put_rgb		(SwfdecOut *	out,
-						 SwfdecColor	color);
-void		swfdec_out_put_rgba		(SwfdecOut *	out,
-						 SwfdecColor	color);
-void		swfdec_out_put_rect		(SwfdecOut *	out,
-						 SwfdecRect *	rect);
+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_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
diff --git a/test/swfedit.c b/test/swfedit.c
index 258f25e..7e13bd6 100644
--- a/test/swfedit.c
+++ b/test/swfedit.c
@@ -33,12 +33,13 @@ save (GtkButton *button, SwfeditFile *fi
   dialog = gtk_file_chooser_dialog_new ("Save file...",
       GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
       GTK_FILE_CHOOSER_ACTION_SAVE,
-      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-      GTK_STOCK_SAVE, GTK_RESPONSE_OK, 
+      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_OK) {
+  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)) {
@@ -70,6 +71,7 @@ open_window (char *filename)
   GError *error = NULL;
   GtkTreeViewColumn *column;
   GtkCellRenderer *renderer;
+  char *basename;
 
   file = swfedit_file_new (filename, &error);
   if (file == NULL) {
@@ -78,7 +80,11 @@ open_window (char *filename)
     return FALSE;
   }
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (window), filename);
+  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);
@@ -92,7 +98,7 @@ open_window (char *filename)
 
   renderer = gtk_cell_renderer_text_new ();
   column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
-    "text", SWFEDIT_COLUMN_NAME, NULL);
+    "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);
 
@@ -100,7 +106,8 @@ open_window (char *filename)
   g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
   g_signal_connect (renderer, "edited", G_CALLBACK (cell_renderer_edited), file);
   column = gtk_tree_view_column_new_with_attributes ("Value", renderer,
-    "text", SWFEDIT_COLUMN_VALUE, "visible", SWFEDIT_COLUMN_VALUE_VISIBLE, NULL);
+    "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);
 
diff --git a/test/swfedit_file.c b/test/swfedit_file.c
index dd5e035..165cde7 100644
--- a/test/swfedit_file.c
+++ b/test/swfedit_file.c
@@ -125,9 +125,9 @@ swf_parse_header1 (SwfeditFile *file, Sw
 static void
 swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits)
 {
-  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rect", SWFEDIT_TOKEN_RECT);
-  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rate", SWFEDIT_TOKEN_UINT16);
-  swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "frames", SWFEDIT_TOKEN_UINT16);
+  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
@@ -254,7 +254,6 @@ swfedit_file_write (SwfeditFile *file)
   swfdec_out_put_u8 (out, 'W');
   swfdec_out_put_u8 (out, 'S');
   swfedit_tag_write_token (token, out, 0);
-  g_print ("length: %u", swfdec_buffer_queue_get_depth (queue));
   swfdec_out_put_u32 (out, swfdec_buffer_queue_get_depth (queue) + 8);
   swfdec_out_prepare_bytes (out, swfdec_buffer_queue_get_depth (queue));
   while ((buffer = swfdec_buffer_queue_pull_buffer (queue))) {
diff --git a/test/swfedit_list.c b/test/swfedit_list.c
new file mode 100644
index 0000000..35ab0a3
--- /dev/null
+++ b/test/swfedit_list.c
@@ -0,0 +1,129 @@
+/* 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);
+    }
+  }
+  /* maybe add items */
+  if (i == token->tokens->len - 1) {
+    g_print ("add fett neue items, man!\n");
+    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 (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);
+  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++) {
+      swfedit_tag_read_tag (SWFEDIT_TOKEN (list), bits, def);
+    }
+    offset += list->n_defs;
+  }
+  return list;
+}
+
diff --git a/test/swfedit_list.h b/test/swfedit_list.h
new file mode 100644
index 0000000..d51ae73
--- /dev/null
+++ b/test/swfedit_list.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_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	(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
index dd15978..c8cf442 100644
--- a/test/swfedit_tag.c
+++ b/test/swfedit_tag.c
@@ -25,20 +25,40 @@
 #include <gtk/gtk.h>
 
 #include <libswfdec/swfdec_bits.h>
+#include <libswfdec/swfdec_debug.h>
+#include <libswfdec/swfdec_script.h>
 #include <libswfdec/swfdec_tag.h>
 #include "swfedit_tag.h"
 #include "swfdec_out.h"
+#include "swfedit_list.h"
 
 /*** LOAD/SAVE ***/
 
 static void
-swfedit_binary_write (gpointer data, SwfdecOut *out)
+swfedit_object_write (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 (SwfdecBits *bits, gconstpointer hint)
+{
+  return swfedit_list_new_read (bits, hint);
+}
+
+static void
+swfedit_binary_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_buffer (out, data);
 }
 
 static gpointer
-swfedit_binary_read (SwfdecBits *bits)
+swfedit_binary_read (SwfdecBits *bits, gconstpointer hint)
 {
   SwfdecBuffer *buffer = swfdec_bits_get_buffer (bits, -1);
   if (buffer == NULL)
@@ -47,91 +67,171 @@ swfedit_binary_read (SwfdecBits *bits)
 }
 
 static void
-swfedit_u8_write (gpointer data, SwfdecOut *out)
+swfedit_bit_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_bit (out, data ? TRUE : FALSE);
+}
+
+static gpointer
+swfedit_bit_read (SwfdecBits *bits, gconstpointer hint)
+{
+  return GUINT_TO_POINTER (swfdec_bits_getbit (bits) ? 1 : 0);
+}
+
+static void
+swfedit_u8_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_u8 (out, GPOINTER_TO_UINT (data));
 }
 
 static gpointer
-swfedit_u8_read (SwfdecBits *bits)
+swfedit_u8_read (SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_u8 (bits));
 }
 
 static void
-swfedit_u16_write (gpointer data, SwfdecOut *out)
+swfedit_u16_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_u16 (out, GPOINTER_TO_UINT (data));
 }
 
 static gpointer
-swfedit_u16_read (SwfdecBits *bits)
+swfedit_u16_read (SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_u16 (bits));
 }
 
 static void
-swfedit_u32_write (gpointer data, SwfdecOut *out)
+swfedit_u32_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_u32 (out, GPOINTER_TO_UINT (data));
 }
 
 static gpointer
-swfedit_u32_read (SwfdecBits *bits)
+swfedit_u32_read (SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_u32 (bits));
 }
 
 static void
-swfedit_rect_write (gpointer data, SwfdecOut *out)
+swfedit_rect_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_rect (out, data);
 }
 
 static gpointer
-swfedit_rect_read (SwfdecBits *bits)
+swfedit_rect_read (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_rgb_write (gpointer data, SwfdecOut *out)
+swfedit_string_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_string (out, data);
+}
+
+static gpointer
+swfedit_string_read (SwfdecBits *bits, gconstpointer hint)
+{
+  char *s;
+  s = swfdec_bits_get_string (bits);
+  if (s == NULL)
+    s = g_strdup ("");
+  return s;
+}
+
+static void
+swfedit_rgb_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_rgb (out, GPOINTER_TO_UINT (data));
 }
 
 static gpointer
-swfedit_rgb_read (SwfdecBits *bits)
+swfedit_rgb_read (SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_color (bits));
 }
 
 static void
-swfedit_rgba_write (gpointer data, SwfdecOut *out)
+swfedit_rgba_write (gpointer data, SwfdecOut *out, gconstpointer hint)
 {
   swfdec_out_put_rgba (out, GPOINTER_TO_UINT (data));
 }
 
 static gpointer
-swfedit_rgba_read (SwfdecBits *bits)
+swfedit_rgba_read (SwfdecBits *bits, gconstpointer hint)
 {
   return GUINT_TO_POINTER (swfdec_bits_get_rgba (bits));
 }
 
+static void
+swfedit_matrix_write (gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_matrix (out, data);
+}
+
+static gpointer
+swfedit_matrix_read (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 (gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  swfdec_out_put_color_transform (out, data);
+}
+
+static gpointer
+swfedit_ctrans_read (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 (gpointer data, SwfdecOut *out, gconstpointer hint)
+{
+  SwfdecScript *script = data;
+
+  swfdec_out_put_buffer (out, script->buffer);
+}
+
+static gpointer
+swfedit_script_read (SwfdecBits *bits, gconstpointer hint)
+{
+  return swfdec_script_new (bits, "original script", 6 /* FIXME */);
+}
+
 struct {
-  void		(* write)	(gpointer data, SwfdecOut *out);
-  gpointer	(* read)	(SwfdecBits *bits);
+  void		(* write)	(gpointer data, SwfdecOut *out, gconstpointer hint);
+  gpointer	(* read)	(SwfdecBits *bits, gconstpointer hint);
 } operations[SWFEDIT_N_TOKENS] = {
-  { NULL, NULL },
+  { 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 },
 };
 
 void
@@ -145,27 +245,30 @@ swfedit_tag_write_token (SwfeditToken *t
   entry = &g_array_index (token->tokens, 
       SwfeditTokenEntry, i);
   g_assert (operations[entry->type].write != NULL);
-  operations[entry->type].write (entry->value, out);
+  operations[entry->type].write (entry->value, out, NULL);
 }
 
 SwfdecBuffer *
-swfedit_tag_write (SwfeditTag *tag)
+swfedit_tag_write (SwfeditToken *token)
 {
   guint i;
   SwfdecOut *out;
 
-  g_return_val_if_fail (SWFEDIT_IS_TAG (tag), NULL);
+  g_return_val_if_fail (SWFEDIT_IS_TOKEN (token), NULL);
 
   out = swfdec_out_open ();
-  for (i = 0; i < SWFEDIT_TOKEN (tag)->tokens->len; i++) {
-    swfedit_tag_write_token (SWFEDIT_TOKEN (tag), out, i);
+  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)
+    const char *name, SwfeditTokenType type, gconstpointer hint)
 {
   gpointer data;
 
@@ -173,25 +276,49 @@ swfedit_tag_read_token (SwfeditToken *to
   g_return_if_fail (name != NULL);
   
   g_assert (operations[type].read != NULL);
-  data = operations[type].read (bits);
+  data = operations[type].read (bits, hint);
+  if (type == SWFEDIT_TOKEN_OBJECT)
+    SWFEDIT_TOKEN (data)->parent = token;
   swfedit_token_add (token, name, type, data);
 }
 
 /*** TAGS ***/
 
-typedef struct {
-  const char *	  	name;			/* name to use for this field */
-  SwfeditTokenType     	type;			/* type of this field */
-  guint			n_items;		/* field to look at for item count (or 0 to use 1 item) */
-  guint			hint;			/* hint to pass to field when creating */
-} SwfeditTagDefinition;
-
-static const SwfeditTagDefinition ShowFrame[] = { { NULL, 0, 0, 0 } };
-static const SwfeditTagDefinition SetBackgroundColor[] = { { "color", SWFEDIT_TOKEN_RGB, 0, 0 }, { NULL, 0, 0, 0 } };
+static const SwfeditTagDefinition 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_UINT32, 0, NULL },
+  { "reserved", SWFEDIT_TOKEN_UINT16, 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, 3, 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 }, 
+  { "all flags", SWFEDIT_TOKEN_UINT32, 1, NULL },
+  { "actions", SWFEDIT_TOKEN_OBJECT, 1, PlaceObject2Action },
+  { NULL, 0, 0, NULL }
+};
 
 static const SwfeditTagDefinition *tags[] = {
   [SWFDEC_TAG_SHOWFRAME] = ShowFrame,
   [SWFDEC_TAG_SETBACKGROUNDCOLOR] = SetBackgroundColor,
+  [SWFDEC_TAG_PLACEOBJECT2] = PlaceObject2,
 };
 
 static const SwfeditTagDefinition *
@@ -215,11 +342,32 @@ swfedit_tag_dispose (GObject *object)
 }
 
 static void
-swfedit_tag_class_init (SwfeditTagClass *class)
+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);
+    }
+  }
+}
+
+static void
+swfedit_tag_class_init (SwfeditTagClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  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
@@ -227,6 +375,54 @@ 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)
 {
@@ -243,7 +439,11 @@ swfedit_tag_new (SwfeditToken *parent, g
     SwfdecBits bits;
     swfdec_bits_init (&bits, buffer);
     for (;def->name != NULL; def++) {
-      swfedit_tag_read_token (SWFEDIT_TOKEN (item), &bits, def->name, def->type);
+      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);
diff --git a/test/swfedit_tag.h b/test/swfedit_tag.h
index 46fdb5f..2f1d231 100644
--- a/test/swfedit_tag.h
+++ b/test/swfedit_tag.h
@@ -21,6 +21,7 @@
 #define __SWFEDIT_TAG_H__
 
 #include <libswfdec/swfdec_buffer.h>
+#include <libswfdec/swfdec_bits.h>
 #include "swfdec_out.h"
 #include "swfedit_token.h"
 
@@ -28,6 +29,14 @@ 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))
@@ -52,14 +61,22 @@ SwfeditTag *	swfedit_tag_new		(SwfeditTo
 					 guint			tag,
 					 SwfdecBuffer *		buffer);
 
-SwfdecBuffer *	swfedit_tag_write	(SwfeditTag *		tag);
+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);
+					 SwfeditTokenType	type,
+					 gconstpointer		hint);
+void		swfedit_tag_read_tag	(SwfeditToken *		token,
+					 SwfdecBits *		bits, 
+					 const SwfeditTagDefinition *def);
 
 G_END_DECLS
 
diff --git a/test/swfedit_token.c b/test/swfedit_token.c
index f3f2bcc..9155b94 100644
--- a/test/swfedit_token.c
+++ b/test/swfedit_token.c
@@ -26,6 +26,7 @@
 #include <gtk/gtk.h>
 #include <libswfdec/swfdec_buffer.h>
 #include <libswfdec/swfdec_color.h>
+#include <libswfdec/swfdec_script.h>
 #include "swfedit_token.h"
 
 /*** CONVERTERS ***/
@@ -57,6 +58,12 @@ swfedit_parse_hex (const char *s, guint 
   return TRUE;
 }
 
+static gpointer
+swfedit_binary_new (void)
+{
+  return swfdec_buffer_new ();
+}
+
 static gboolean
 swfedit_binary_from_string (const char *s, gpointer* result)
 {
@@ -101,6 +108,24 @@ swfedit_binary_to_string (gconstpointer 
 }
 
 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;
@@ -140,6 +165,25 @@ swfedit_to_string_unsigned (gconstpointe
   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)
 {
@@ -212,21 +256,129 @@ swfedit_rgba_to_string (gconstpointer va
       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)
+{
+  SwfdecBuffer *buffer;
+  SwfdecBits bits;
+  SwfdecScript *script;
+  
+  if (swfedit_binary_from_string (s, (gpointer *) &buffer))
+    return FALSE;
+
+  swfdec_bits_init (&bits, buffer);
+  script = swfdec_script_new (&bits, "unknown", 6 /* FIXME */);
+  swfdec_buffer_unref (buffer);
+  if (script != NULL) {
+    *result = script;
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+static char *
+swfedit_script_to_string (gconstpointer value)
+{
+  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, g_object_unref },
-  { swfedit_binary_from_string, swfedit_binary_to_string, (GDestroyNotify) swfdec_buffer_unref },
-  { swfedit_uint8_from_string, swfedit_to_string_unsigned, NULL },
-  { swfedit_uint16_from_string, swfedit_to_string_unsigned, NULL },
-  { swfedit_uint32_from_string, swfedit_to_string_unsigned, NULL },
-  { swfedit_rect_from_string, swfedit_rect_to_string, g_free },
-  { swfedit_rgb_from_string, swfedit_rgb_to_string, NULL },
-  { swfedit_rgba_from_string, swfedit_rgba_to_string, NULL },
+  { 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 },
 };
 
+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
@@ -259,6 +411,8 @@ swfedit_token_get_column_type (GtkTreeMo
       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:
@@ -343,6 +497,10 @@ swfedit_token_get_value (GtkTreeModel *t
       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)
@@ -529,14 +687,16 @@ swfedit_token_new (void)
 }
 
 void
-swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, gpointer value)
+swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, 
+    gpointer value)
 {
-  SwfeditTokenEntry entry = { NULL, type, 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);
 }
@@ -544,6 +704,7 @@ swfedit_token_add (SwfeditToken *token, 
 void
 swfedit_token_set (SwfeditToken *token, GtkTreeIter *iter, const char *value)
 {
+  SwfeditTokenClass *klass;
   GtkTreeModel *model;
   SwfeditTokenEntry *entry;
   guint i;
@@ -565,9 +726,38 @@ swfedit_token_set (SwfeditToken *token, 
   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
index 7909188..53c3b62 100644
--- a/test/swfedit_token.h
+++ b/test/swfedit_token.h
@@ -28,19 +28,25 @@ 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_N_TOKENS
 } SwfeditTokenType;
 
 typedef enum {
   SWFEDIT_COLUMN_NAME,
   SWFEDIT_COLUMN_VALUE_VISIBLE,
-  SWFEDIT_COLUMN_VALUE
+  SWFEDIT_COLUMN_VALUE,
+  SWFEDIT_COLUMN_VALUE_EDITABLE
 } SwfeditColumn;
 
 typedef struct _SwfeditTokenEntry SwfeditTokenEntry;
@@ -59,6 +65,7 @@ struct _SwfeditTokenEntry {
   char *		name;
   SwfeditTokenType	type;
   gpointer		value;
+  gboolean		visible;
 };
 
 struct _SwfeditToken {
@@ -71,10 +78,15 @@ struct _SwfeditToken {
 
 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,
@@ -83,6 +95,9 @@ void		swfedit_token_add		(SwfeditToken *
 void		swfedit_token_set		(SwfeditToken *		token,
 						 GtkTreeIter *		iter,
 						 const char *		value);
+void		swfedit_token_set_visible	(SwfeditToken *		token,
+						 guint			i,
+						 gboolean		visible);
 
 
 G_END_DECLS
diff-tree 4a5112ee3285fd9cf3ba55bece78c2110c40cace (from parents)
Merge: f7d6b3d314017ad0ffbd22cd559cf8204c7729cf f4932b1cc75a7e82fa6af103371579096454eb8e
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Feb 12 10:17:16 2007 +0100

    Merge branch 'master' of ssh://company@git.freedesktop.org/git/swfdec

diff-tree f7d6b3d314017ad0ffbd22cd559cf8204c7729cf (from e09255e66fe4990bd8531519ae20da81a4beb4f4)
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Feb 9 14:28:38 2007 +0100

    first simple and incomplete implementation of GetURL2

diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index 74b9934..bf0fb07 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -1062,6 +1062,44 @@ swfdec_action_get_url (JSContext *cx, gu
 }
 
 static JSBool
+swfdec_action_get_url2 (JSContext *cx, guint action, const guint8 *data, guint len)
+{
+  const char *target, *url;
+  guint method;
+  SwfdecMovie *movie;
+
+  if (len != 1) {
+    SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len);
+    return JS_FALSE;
+  }
+  target = swfdec_js_to_string (cx, cx->fp->sp[-1]);
+  url = swfdec_js_to_string (cx, cx->fp->sp[-2]);
+  if (target == NULL || url == NULL)
+    return JS_FALSE;
+  method = data[0] >> 6;
+  if (method == 3) {
+    SWFDEC_ERROR ("GetURL method 3 invalid");
+    method = 0;
+  }
+  if (method) {
+    SWFDEC_ERROR ("FIXME: implement encoding variables using %s", method == 1 ? "GET" : "POST");
+  }
+  if (data[0] & 2) {
+    SWFDEC_ERROR ("FIXME: implement LoadTarget");
+  }
+  if (data[0] & 1) {
+    SWFDEC_ERROR ("FIXME: implement LoadVariables");
+  }
+  movie = swfdec_action_get_target (cx);
+  if (movie)
+    swfdec_root_movie_load (SWFDEC_ROOT_MOVIE (movie->root), url, target);
+  else
+    SWFDEC_WARNING ("no movie to load");
+  cx->fp->sp -= 2;
+  return JS_TRUE;
+}
+
+static JSBool
 swfdec_action_string_add (JSContext *cx, guint action, const guint8 *data, guint len)
 {
   JSString *lval, *rval;
@@ -1940,7 +1978,7 @@ static const SwfdecActionSpec actions[25
   /* version 4 */
   [0x96] = { "Push", swfdec_action_print_push, 0, -1, { NULL, swfdec_action_push, swfdec_action_push, swfdec_action_push, swfdec_action_push } },
   [0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } },
-  [0x9a] = { "GetURL2", NULL },
+  [0x9a] = { "GetURL2", NULL, 2, 0, { NULL, swfdec_action_get_url2, swfdec_action_get_url2, swfdec_action_get_url2, swfdec_action_get_url2 } },
   /* version 5 */
   [0x9b] = { "DefineFunction", swfdec_action_print_define_function, 0, -1, { NULL, NULL, swfdec_action_define_function, swfdec_action_define_function, swfdec_action_define_function } },
   /* version 4 */
diff-tree e09255e66fe4990bd8531519ae20da81a4beb4f4 (from fa496c4d6ae5187e39c1b77cf7b13517be873a3c)
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Feb 9 14:03:11 2007 +0100

    use swfdec_bits_decompress
    
    contains various bugfixing

diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c
index ab62969..0dee685 100644
--- a/libswfdec/swfdec_image.c
+++ b/libswfdec/swfdec_image.c
@@ -89,47 +89,6 @@ swfdec_image_init (SwfdecImage * image)
 {
 }
 
-
-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 guint8 *
-lossless (const guint8 *zptr, int zlen, int len)
-{
-  guint8 *data;
-  z_stream z = { NULL, };
-  int ret;
-
-  z.zalloc = zalloc;
-  z.zfree = zfree;
-  z.opaque = NULL;
-
-  data = g_malloc (len);
-  z.next_in = (Bytef *) zptr;
-  z.avail_in = zlen;
-  z.next_out = data;
-  z.avail_out = len;
-
-  ret = inflateInit (&z);
-  ret = inflate (&z, Z_FINISH);
-  if (ret != Z_STREAM_END) {
-    SWFDEC_WARNING ("lossless: ret == %d", ret);
-  }
-  inflateEnd (&z);
-
-  return data;
-}
-
-
 int
 swfdec_image_jpegtables (SwfdecSwfDecoder * s)
 {
@@ -267,7 +226,6 @@ static void
 swfdec_image_jpeg3_load (SwfdecImage *image)
 {
   JpegRGBDecoder *dec;
-  unsigned char *alpha_data;
   SwfdecBits bits;
   SwfdecBuffer *buffer;
   int jpeg_length;
@@ -294,12 +252,13 @@ swfdec_image_jpeg3_load (SwfdecImage *im
       &image->rowstride, &image->width, &image->height);
   jpeg_rgb_decoder_free (dec);
 
-  buffer = swfdec_bits_get_buffer (&bits, -1);
-  alpha_data = lossless (buffer->data, buffer->length, image->width * image->height);
-  swfdec_buffer_unref (buffer);
-
-  merge_alpha (image, image->data, alpha_data);
-  g_free (alpha_data);
+  buffer = swfdec_bits_decompress (&bits, -1, image->width * image->height);
+  if (buffer) {
+    merge_alpha (image, image->data, buffer->data);
+    swfdec_buffer_unref (buffer);
+  } else {
+    SWFDEC_WARNING ("cannot set alpha channel information, decompression failed");
+  }
 
   SWFDEC_LOG ("  width = %d", image->width);
   SWFDEC_LOG ("  height = %d", image->height);
@@ -355,6 +314,7 @@ swfdec_image_lossless_load (SwfdecImage 
   swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height);
 
   if (format == 3) {
+    SwfdecBuffer *buffer;
     unsigned char *indexed_data;
     guint i;
     unsigned int rowstride = (image->width + 3) & ~3;
@@ -363,8 +323,13 @@ swfdec_image_lossless_load (SwfdecImage 
     image->rowstride = image->width * 4;
 
     if (have_alpha) {
-      ptr = lossless (bits.ptr, bits.end - bits.ptr, 
-	  color_table_size * 4 + rowstride * image->height);
+      buffer = swfdec_bits_decompress (&bits, -1, color_table_size * 4 + rowstride * image->height);
+      if (buffer == NULL) {
+	SWFDEC_ERROR ("failed to decompress data");
+	memset (image->data, 0, 4 * image->width * image->height);
+	return;
+      }
+      ptr = buffer->data;
       for (i = 0; i < color_table_size; i++) {
 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
 	guint8 tmp = ptr[i * 4 + 0];
@@ -380,8 +345,13 @@ swfdec_image_lossless_load (SwfdecImage 
       }
       indexed_data = ptr + color_table_size * 4;
     } else {
-      ptr = lossless (bits.ptr, bits.end - bits.ptr, 
-	  color_table_size * 3 + rowstride * image->height);
+      buffer = swfdec_bits_decompress (&bits, -1, color_table_size * 3 + rowstride * image->height);
+      if (buffer == NULL) {
+	SWFDEC_ERROR ("failed to decompress data");
+	memset (image->data, 0, 4 * image->width * image->height);
+	return;
+      }
+      ptr = buffer->data;
       for (i = color_table_size - 1; i < color_table_size; i--) {
 	guint8 color[3];
 	color[0] = ptr[i * 3 + 0];
@@ -404,27 +374,33 @@ swfdec_image_lossless_load (SwfdecImage 
     swfdec_image_colormap_decode (image, image->data, indexed_data,
 	ptr, color_table_size);
 
-    g_free (ptr);
+    swfdec_buffer_unref (buffer);
   } else if (format == 4) {
     int i, j;
     unsigned int c;
     unsigned char *idata;
-    guint8 *p;
+    SwfdecBuffer *buffer;
 
     if (have_alpha) {
       SWFDEC_INFO("16bit images aren't allowed to have alpha, ignoring");
       have_alpha = FALSE;
     }
 
-    p = ptr = lossless (bits.ptr, bits.end - bits.ptr, 2 * image->width * image->height);
+    buffer = swfdec_bits_decompress (&bits, -1, 2 * ((image->width + 1) & ~1) * image->height);
     image->data = g_malloc (4 * image->width * image->height);
     idata = image->data;
     image->rowstride = image->width * 4;
+    if (buffer == NULL) {
+      SWFDEC_ERROR ("failed to decompress data");
+      memset (image->data, 0, 4 * image->width * image->height);
+      return;
+    }
+    ptr = buffer->data;
 
     /* 15 bit packed */
     for (j = 0; j < image->height; j++) {
       for (i = 0; i < image->width; i++) {
-        c = p[1] | (p[0] << 8);
+        c = ptr[1] | (ptr[0] << 8);
         idata[SWFDEC_COLOR_INDEX_BLUE] = (c << 3) | ((c >> 2) & 0x7);
         idata[SWFDEC_COLOR_INDEX_GREEN] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7);
         idata[SWFDEC_COLOR_INDEX_RED] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7);
@@ -432,12 +408,22 @@ swfdec_image_lossless_load (SwfdecImage 
         ptr += 2;
         idata += 4;
       }
+      if (image->width & 1)
+	ptr += 2;
     }
-    g_free (ptr);
+    swfdec_buffer_unref (buffer);
   }
   if (format == 5) {
+    SwfdecBuffer *buffer;
     int i, j;
-    ptr = image->data = lossless (bits.ptr, bits.end - bits.ptr, 4 * image->width * image->height);
+    buffer = swfdec_bits_decompress (&bits, -1, 4 * image->width * image->height);
+    image->rowstride = 4 * image->width;
+    if (buffer == NULL) {
+      SWFDEC_ERROR ("failed to decompress data");
+      image->data = g_malloc0 (4 * image->width * image->height);
+      return;
+    }
+    ptr = image->data = buffer->data;
     /* image is stored in 0RGB format.  We use ARGB/BGRA. */
     for (j = 0; j < image->height; j++) {
       for (i = 0; i < image->width; i++) {
@@ -445,6 +431,11 @@ swfdec_image_lossless_load (SwfdecImage 
 	ptr += 4;
       }
     }
+    /* FIXME: this can fail if the returned buffer does not contain malloc'd 
+     * data at some point in the future */
+    buffer->data = NULL;
+    buffer->length = 0;
+    swfdec_buffer_unref (buffer);
   }
 }
 
diff-tree fa496c4d6ae5187e39c1b77cf7b13517be873a3c (from 34f26f78afcd7e08945729f409872fce624d9cef)
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Feb 9 14:02:50 2007 +0100

    use swfdec_bits_decompress instead of doing it manually

diff --git a/libswfdec/swfdec_codec_screen.c b/libswfdec/swfdec_codec_screen.c
index de21d21..0ba59f0 100644
--- a/libswfdec/swfdec_codec_screen.c
+++ b/libswfdec/swfdec_codec_screen.c
@@ -35,35 +35,13 @@ struct _SwfdecCodecScreen {
   guint			width;		/* width of last image */
   guint			height;		/* height of last image */
   SwfdecBuffer *	buffer;		/* buffer containing last decoded image */
-  z_stream		z;		/* stream for decoding */
-  SwfdecBuffer *	block_buffer;	/* buffer used for block decoding */
 };
 
-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 gpointer
 swfdec_codec_screen_init (void)
 {
   SwfdecCodecScreen *screen = g_new0 (SwfdecCodecScreen, 1);
 
-  screen->z.zalloc = zalloc;
-  screen->z.zfree = zfree;
-  screen->z.opaque = NULL;
-  if (inflateInit (&screen->z) != Z_OK) {
-    SWFDEC_ERROR ("Error initialising zlib: %s", screen->z.msg);
-    g_free (screen);
-    return NULL;
-  }
   return screen;
 }
 
@@ -107,11 +85,6 @@ swfdec_codec_screen_decode (gpointer cod
     /* FIXME: this is was ffmpeg does, should we be more forgiving? */
     return NULL;
   }
-  if (screen->block_buffer == NULL || screen->block_buffer->length < bw * bh * 3) {
-    if (screen->block_buffer != NULL)
-      swfdec_buffer_unref (screen->block_buffer);
-    screen->block_buffer = swfdec_buffer_new_and_alloc (bw * bh * 3);
-  }
   if (screen->buffer && screen->buffer->ref_count == 1) {
     g_assert (screen->buffer->length == w * h * 4);
     swfdec_buffer_ref (screen->buffer);
@@ -130,49 +103,26 @@ swfdec_codec_screen_decode (gpointer cod
   SWFDEC_LOG ("size: %u x %u - block size %u x %u\n", w, h, bw, bh);
   for (j = 0; j < h; j += bh) {
     for (i = 0; i < w; i += bw) {
-      int result;
       guint x, y, size;
+      SwfdecBuffer *buffer;
       guint8 *in, *out;
-      /* decode the block into block_buffer */
       size = swfdec_bits_get_bu16 (&bits);
       if (size == 0)
 	continue;
-      if (inflateReset(&screen->z) != Z_OK) {
-	SWFDEC_ERROR ("error resetting zlib decoder: %s", screen->z.msg);
-      }
-      screen->z.next_in = (void *) bits.ptr;
-      if (swfdec_bits_skip_bytes (&bits, size) != size) {
-	SWFDEC_ERROR ("not enough bytes available");
-	return NULL;
-      }
-      screen->z.avail_in = size;
-      screen->z.next_out = screen->block_buffer->data;
-      screen->z.avail_out = screen->block_buffer->length;
-      result = inflate (&screen->z, Z_FINISH);
-      if (result == Z_DATA_ERROR) {
-	inflateSync (&screen->z);
-	result = inflate (&screen->z, Z_FINISH);
-      }
-      if (result < 0) {
-	SWFDEC_WARNING ("error decoding block: %s", screen->z.msg);
+      buffer = swfdec_bits_decompress (&bits, size, bw * bh * 4);
+      if (buffer == NULL) {
+	SWFDEC_WARNING ("error decoding block");
 	continue;
       }
       /* convert format and write out data */
       out = ret->data + stride * (h - j - 1) + i * 4;
-      in = screen->block_buffer->data;
+      in = buffer->data;
       for (y = 0; y < MIN (bh, h - j); y++) {
 	for (x = 0; x < MIN (bw, w - i); x++) {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-	  out[x * 4 - y * stride] = *in++;
-	  out[x * 4 - y * stride + 1] = *in++;
-	  out[x * 4 - y * stride + 2] = *in++;
-	  out[x * 4 - y * stride + 3] = 0xFF;
-#else
-	  out[x * 4 - y * stride + 3] = *in++;
-	  out[x * 4 - y * stride + 2] = *in++;
-	  out[x * 4 - y * stride + 1] = *in++;
-	  out[x * 4 - y * stride] = 0xFF;
-#endif
+	  out[x * 4 - y * stride + SWFDEC_COLOR_INDEX_BLUE] = *in++;
+	  out[x * 4 - y * stride + SWFDEC_COLOR_INDEX_GREEN] = *in++;
+	  out[x * 4 - y * stride + SWFDEC_COLOR_INDEX_RED] = *in++;
+	  out[x * 4 - y * stride + SWFDEC_COLOR_INDEX_ALPHA] = 0xFF;
 	}
       }
     }
diff-tree 34f26f78afcd7e08945729f409872fce624d9cef (from bca06937c45d0d89271681e0dbd3a2fbeeaa9dd0)
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Feb 9 14:02:27 2007 +0100

    Add swfdec_bits_decompress for zlib decompression of data

diff --git a/libswfdec/swfdec_bits.c b/libswfdec/swfdec_bits.c
index 21172f2..6a9ed33 100644
--- a/libswfdec/swfdec_bits.c
+++ b/libswfdec/swfdec_bits.c
@@ -1,7 +1,7 @@
 /* Swfdec
  * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
  *		 2005-2006 Eric Anholt <eric at anholt.net>
- *		      2006 Benjamin Otte <otte at gnome.org>
+ *		 2006-2007 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,6 +24,7 @@
 #endif
 
 #include <string.h>
+#include <zlib.h>
 
 #include "swfdec_bits.h"
 #include "swfdec_debug.h"
@@ -600,3 +601,108 @@ swfdec_bits_get_buffer (SwfdecBits *bits
   bits->ptr += len;
   return buffer;
 }
+
+static void *
+swfdec_bits_zalloc (void *opaque, unsigned int items, unsigned int size)
+{
+  return g_malloc (items * size);
+}
+
+static void
+swfdec_bits_zfree (void *opaque, void *addr)
+{
+  g_free (addr);
+}
+
+/**
+ * swfdec_bits_decompress:
+ * @bits: a #SwfdecBits
+ * @compressed: number of bytes to decompress or -1 for the rest
+ * @decompressed: number of bytes to expect in the decompressed result or -1
+ *                if unknown
+ *
+ * Decompresses the next @compressed bytes of data in @bits using the zlib
+ * decompression algorithm and returns the result in a buffer. If @decompressed
+ * was set and not enough data is available, the return buffer will be filled 
+ * up with 0 bytes.
+ *
+ * Returns: a new #SwfdecBuffer containing the decompressed data or NULL on
+ *          failure. If @decompressed &gt; 0, the buffer's length will be @decompressed.
+ **/
+SwfdecBuffer *
+swfdec_bits_decompress (SwfdecBits *bits, int compressed, int decompressed)
+{
+  z_stream z = { 0, };
+  SwfdecBuffer *buffer;
+  int result;
+
+  g_return_val_if_fail (bits != NULL, NULL);
+  g_return_val_if_fail (compressed >= -1, NULL);
+  g_return_val_if_fail (decompressed > 0 || decompressed == -1, NULL);
+
+  /* prepare the bits structure */
+  if (compressed > 0) {
+    SWFDEC_BYTES_CHECK (bits, (unsigned int) compressed);
+  } else {
+    swfdec_bits_syncbits (bits);
+    compressed = bits->end - bits->ptr;
+    g_assert (compressed >= 0);
+  }
+  if (compressed == 0)
+    return NULL;
+
+  z.zalloc = swfdec_bits_zalloc;
+  z.zfree = swfdec_bits_zfree;
+  z.opaque = NULL;
+  z.next_in = (Bytef *) bits->ptr;
+  z.avail_in = compressed;
+  result = inflateInit (&z);
+  if (result != Z_OK) {
+    SWFDEC_ERROR ("Error initialising zlib: %d %s", result, z.msg ? z.msg : "");
+    goto fail;
+  }
+  buffer = swfdec_buffer_new_and_alloc (decompressed > 0 ? decompressed : compressed * 2);
+  z.next_out = buffer->data;
+  z.avail_out = buffer->length;
+  while (TRUE) {
+    result = inflate (&z, decompressed > 0 ? Z_FINISH : 0);
+    switch (result) {
+      case Z_STREAM_END:
+	goto out;
+      case Z_OK:
+	if (decompressed < 0) {
+	  buffer->data = g_realloc (buffer->data, buffer->length + compressed);
+	  buffer->length += compressed;
+	  z.next_out = buffer->data + z.total_out;
+	  z.avail_out = buffer->length - z.total_out;
+	  goto out;
+	}
+	/* else fall through */
+      default:
+	SWFDEC_ERROR ("error decompressing data: inflate returned %d %s",
+	    result, z.msg ? z.msg : "");
+	swfdec_buffer_unref (buffer);
+	goto fail;
+    }
+  }
+out:
+  if (decompressed < 0) {
+    buffer->length = z.total_out;
+  } else {
+    if (buffer->length < z.total_out) {
+      SWFDEC_WARNING ("Not enough data decompressed: %lu instead of %u expected",
+	  z.total_out, buffer->length);
+      memset (buffer->data + z.total_out, 0, buffer->length - z.total_out);
+    }
+  }
+  result = inflateEnd (&z);
+  if (result != Z_OK) {
+    SWFDEC_ERROR ("error in inflateEnd: %d %s", result, z.msg ? z.msg : "");
+  }
+  bits->ptr += compressed;
+  return buffer;
+
+fail:
+  bits->ptr += compressed;
+  return NULL;
+}
diff --git a/libswfdec/swfdec_bits.h b/libswfdec/swfdec_bits.h
index a44c9e2..0dd1dd9 100644
--- a/libswfdec/swfdec_bits.h
+++ b/libswfdec/swfdec_bits.h
@@ -1,7 +1,7 @@
 /* Swfdec
  * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
  *		 2005-2006 Eric Anholt <eric at anholt.net>
- *		      2006 Benjamin Otte <otte at gnome.org>
+ *		 2006-2007 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -72,6 +72,8 @@ SwfdecGradient *swfdec_bits_get_gradient
 SwfdecGradient *swfdec_bits_get_morph_gradient (SwfdecBits * bits);
 void swfdec_bits_get_rect (SwfdecBits * bits, SwfdecRect *rect);
 SwfdecBuffer *swfdec_bits_get_buffer (SwfdecBits *bits, int len);
+SwfdecBuffer *swfdec_bits_decompress (SwfdecBits *bits, int compressed, 
+    int decompressed);
 
 
 #endif


More information about the Swfdec mailing list