[Swfdec] Branch 'interpreter' - 3 commits - libswfdec/swfdec_bits.c libswfdec/swfdec_swf_decoder.c test/Makefile.am test/swfedit.c test/swfedit_file.c test/swfedit_file.h test/swfedit_tag.c test/swfedit_tag.h test/swfedit_token.c test/swfedit_token.h

Benjamin Otte company at kemper.freedesktop.org
Mon Jan 22 09:35:06 PST 2007


 libswfdec/swfdec_bits.c        |   27 +-
 libswfdec/swfdec_swf_decoder.c |   46 ----
 test/Makefile.am               |   19 +
 test/swfedit.c                 |   81 +++++++
 test/swfedit_file.c            |  209 ++++++++++++++++++
 test/swfedit_file.h            |   59 +++++
 test/swfedit_tag.c             |   61 +++++
 test/swfedit_tag.h             |   56 ++++
 test/swfedit_token.c           |  464 +++++++++++++++++++++++++++++++++++++++++
 test/swfedit_token.h           |   79 ++++++
 10 files changed, 1054 insertions(+), 47 deletions(-)

New commits:
diff-tree 72caf9482e2e7eb4bdc6cc0fa7578beb31645bac (from ac526c14b6a853304588e1c71ccc0ab709ac072e)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 22 18:34:59 2007 +0100

    add a first shot at an swf file editor that is supposed to allow creating
    broken files for testing purposes when it's done

diff --git a/test/Makefile.am b/test/Makefile.am
index 01c4f45..d168cfd 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,6 +1,10 @@
 SUBDIRS = sound trace various
 
-noinst_PROGRAMS = swfdec-extract dump parse
+if WITH_GTK
+noinst_PROGRAMS = swfdec-extract dump parse swfedit
+else
+noinst_PROGRAMS = swfdec-extract dump parse 
+endif
 
 dump_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
 dump_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
@@ -11,3 +15,16 @@ parse_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS
 swfdec_extract_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
 swfdec_extract_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS)
 
+swfedit_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(GTK_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
+swfedit_LDFLAGS = $(SWF_LIBS) $(GTK_LIBS)
+
+swfedit_SOURCES = \
+	swfedit.c \
+	swfedit_file.c \
+	swfedit_tag.c \
+	swfedit_token.c
+
+noinst_HEADERS = \
+	swfedit_file.h \
+	swfedit_tag.h \
+	swfedit_token.h
diff --git a/test/swfedit.c b/test/swfedit.c
new file mode 100644
index 0000000..76fa744
--- /dev/null
+++ b/test/swfedit.c
@@ -0,0 +1,81 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include "swfedit_file.h"
+
+static gboolean
+open_window (char *filename)
+{
+  SwfeditFile *file;
+  GtkWidget *window, *treeview;
+  GError *error = NULL;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+
+  file = swfedit_file_new (filename, &error);
+  if (file == NULL) {
+    g_printerr ("Error openeing file %s: %s\n", filename, error->message);
+    g_error_free (error);
+    return FALSE;
+  }
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (file));
+  gtk_container_add (GTK_CONTAINER (window), treeview);
+  gtk_widget_show_all (window);
+
+  renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
+    "text", SWFEDIT_COLUMN_NAME, NULL);
+  gtk_tree_view_column_set_resizable (column, TRUE);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
+  column = gtk_tree_view_column_new_with_attributes ("Value", renderer,
+    "text", SWFEDIT_COLUMN_VALUE, "visible", SWFEDIT_COLUMN_VALUE_VISIBLE, NULL);
+  gtk_tree_view_column_set_resizable (column, TRUE);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+
+  return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  if (argc <= 1) {
+    g_print ("Usage: %s FILENAME\n", argv[0]);
+    return 1;
+  }
+  if (open_window (argv[1])) {
+    gtk_main ();
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
diff --git a/test/swfedit_file.c b/test/swfedit_file.c
new file mode 100644
index 0000000..e995c1b
--- /dev/null
+++ b/test/swfedit_file.c
@@ -0,0 +1,209 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <zlib.h>
+
+#include "libswfdec/swfdec_bits.h"
+#include "libswfdec/swfdec_buffer.h"
+#include "libswfdec/swfdec_debug.h"
+#include "swfedit_file.h"
+#include "swfedit_tag.h"
+
+G_DEFINE_TYPE (SwfeditFile, swfedit_file, SWFEDIT_TYPE_TOKEN)
+
+static void
+swfedit_file_dispose (GObject *object)
+{
+  SwfeditFile *file = SWFEDIT_FILE (object);
+
+  g_list_foreach (file->tags, (GFunc) g_object_unref, NULL);
+  g_list_free (file->tags);
+  g_free (file->filename);
+
+  G_OBJECT_CLASS (swfedit_file_parent_class)->dispose (object);
+}
+
+static void *
+zalloc (void *opaque, unsigned int items, unsigned int size)
+{
+  return g_malloc (items * size);
+}
+
+static void
+zfree (void *opaque, void *addr)
+{
+  g_free (addr);
+}
+
+static SwfdecBuffer *
+swfenc_file_inflate (SwfdecBits *bits, guint size)
+{
+  SwfdecBuffer *decoded, *encoded;
+  z_stream z;
+  int ret;
+
+  encoded = swfdec_bits_get_buffer (bits, -1);
+  if (encoded == NULL)
+    return NULL;
+  decoded = swfdec_buffer_new_and_alloc (size);
+  z.zalloc = zalloc;
+  z.zfree = zfree;
+  z.opaque = NULL;
+  z.next_in = encoded->data;
+  z.avail_in = encoded->length;
+  z.next_out = decoded->data;
+  z.avail_out = decoded->length;
+  ret = inflateInit (&z);
+  SWFDEC_DEBUG ("inflateInit returned %d", ret);
+  if (ret >= Z_OK) {
+    ret = inflate (&z, Z_SYNC_FLUSH);
+    SWFDEC_DEBUG ("inflate returned %d", ret);
+  }
+  inflateEnd (&z);
+  swfdec_buffer_unref (encoded);
+  if (ret < Z_OK) {
+    swfdec_buffer_unref (decoded);
+    return NULL;
+  }
+  return decoded;
+}
+
+static SwfdecBuffer *
+swf_parse_header1 (SwfeditFile *file, SwfdecBits *bits, GError **error)
+{
+  guint sig1, sig2, sig3, bytes_total;
+
+  sig1 = swfdec_bits_get_u8 (bits);
+  sig2 = swfdec_bits_get_u8 (bits);
+  sig3 = swfdec_bits_get_u8 (bits);
+  if ((sig1 != 'F' && sig1 != 'C') || sig2 != 'W' || sig3 != 'S') {
+    g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	"This is not a SWF file");
+    return NULL;
+  }
+
+  swfedit_token_add (SWFEDIT_TOKEN (file), "version", SWFEDIT_TOKEN_UINT8, 
+      GUINT_TO_POINTER (swfdec_bits_get_u8 (bits)));
+  bytes_total = swfdec_bits_get_u32 (bits);
+
+  if (sig1 == 'C') {
+    /* compressed */
+    SwfdecBuffer *ret = swfenc_file_inflate (bits, bytes_total);
+    if (ret == NULL)
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	  "Unable to uncompress file");
+    return ret;
+  } else {
+    SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, -1);
+    if (ret == NULL)
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	  "File too small");
+    return ret;
+  }
+}
+
+static void
+swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits)
+{
+  SwfdecRect rect;
+
+  swfdec_bits_get_rect (bits, &rect);
+  swfdec_bits_syncbits (bits);
+  swfedit_token_add (SWFEDIT_TOKEN (file), "rate", SWFEDIT_TOKEN_UINT16, 
+      GUINT_TO_POINTER (swfdec_bits_get_u16 (bits)));
+  swfedit_token_add (SWFEDIT_TOKEN (file), "frames", SWFEDIT_TOKEN_UINT16, 
+      GUINT_TO_POINTER (swfdec_bits_get_u16 (bits)));
+}
+
+static gboolean
+swfedit_file_parse (SwfeditFile *file, SwfdecBits *bits, GError **error)
+{
+  SwfdecBuffer *next;
+  
+  next = swf_parse_header1 (file, bits, error);
+  if (next == NULL)
+    return FALSE;
+  swfdec_bits_init (bits, next);
+  swf_parse_header2 (file, bits);
+
+  while (swfdec_bits_left (bits)) {
+    guint x = swfdec_bits_get_u16 (bits);
+    G_GNUC_UNUSED guint tag = (x >> 6) & 0x3ff;
+    guint tag_len = x & 0x3f;
+    SwfdecBuffer *buffer;
+    SwfeditTag *item;
+    char *name;
+    if (tag_len == 0x3f)
+      tag_len = swfdec_bits_get_u32 (bits);
+    if (tag_len > 0)
+      buffer = swfdec_bits_get_buffer (bits, tag_len);
+    else
+      buffer = swfdec_buffer_new ();
+    if (buffer == NULL) {
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+	  "Invalid contents in file");
+      return FALSE;
+    }
+    item = swfedit_tag_new (tag, buffer);
+    name = g_strdup_printf ("Tag %u", tag);
+    swfedit_token_add (SWFEDIT_TOKEN (file), name, SWFEDIT_TOKEN_OBJECT, item);
+    g_free (name);
+  }
+  swfdec_buffer_unref (next);
+  return TRUE;
+}
+
+static void
+swfedit_file_class_init (SwfeditFileClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = swfedit_file_dispose;
+}
+
+static void
+swfedit_file_init (SwfeditFile *s)
+{
+}
+
+SwfeditFile *
+swfedit_file_new (const char *filename, GError **error)
+{
+  SwfeditFile *file;
+  SwfdecBuffer *buffer;
+  SwfdecBits bits;
+
+  buffer = swfdec_buffer_new_from_file (filename, error);
+  if (buffer == NULL)
+    return NULL;
+  swfdec_bits_init (&bits, buffer);
+  file = g_object_new (SWFEDIT_TYPE_FILE, NULL);
+  file->filename = g_strdup (filename);
+  if (!swfedit_file_parse (file, &bits, error)) {
+    swfdec_buffer_unref (buffer);
+    g_object_unref (file);
+    return NULL;
+  }
+  swfdec_buffer_unref (buffer);
+  return file;
+}
diff --git a/test/swfedit_file.h b/test/swfedit_file.h
new file mode 100644
index 0000000..39a89c5
--- /dev/null
+++ b/test/swfedit_file.h
@@ -0,0 +1,59 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_FILE_H__
+#define __SWFEDIT_FILE_H__
+
+#include <libswfdec/swfdec_rect.h>
+#include "swfedit_token.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SwfeditFile SwfeditFile;
+typedef struct _SwfeditFileClass SwfeditFileClass;
+
+#define SWFEDIT_TYPE_FILE                    (swfedit_file_get_type())
+#define SWFEDIT_IS_FILE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_FILE))
+#define SWFEDIT_IS_FILE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_FILE))
+#define SWFEDIT_FILE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_FILE, SwfeditFile))
+#define SWFEDIT_FILE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_FILE, SwfeditFileClass))
+#define SWFEDIT_FILE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_FILE, SwfeditFileClass))
+
+struct _SwfeditFile {
+  SwfeditToken		token;
+
+  char *		filename;	/* name this file is saved to */
+
+  /* defined objects */
+  GList *		tags;		/* ordered list of all tags in the file */
+};
+
+struct _SwfeditFileClass {
+  SwfeditTokenClass	token_class;
+};
+
+GType		swfedit_file_get_type		(void);
+
+SwfeditFile *	swfedit_file_new		(const char *	filename,
+						 GError **	error);
+
+
+G_END_DECLS
+
+#endif
diff --git a/test/swfedit_tag.c b/test/swfedit_tag.c
new file mode 100644
index 0000000..9bbebeb
--- /dev/null
+++ b/test/swfedit_tag.c
@@ -0,0 +1,61 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include "swfedit_tag.h"
+
+G_DEFINE_TYPE (SwfeditTag, swfedit_tag, SWFEDIT_TYPE_TOKEN)
+
+static void
+swfedit_tag_dispose (GObject *object)
+{
+  //SwfeditTag *tag = SWFEDIT_TAG (object);
+
+  G_OBJECT_CLASS (swfedit_tag_parent_class)->dispose (object);
+}
+
+static void
+swfedit_tag_class_init (SwfeditTagClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = swfedit_tag_dispose;
+}
+
+static void
+swfedit_tag_init (SwfeditTag *tag)
+{
+}
+
+SwfeditTag *
+swfedit_tag_new (guint tag, SwfdecBuffer *buffer)
+{
+  SwfeditTag *item;
+
+  item = g_object_new (SWFEDIT_TYPE_TAG, NULL);
+  item->tag = tag;
+  swfedit_token_add (SWFEDIT_TOKEN (item), "contents", SWFEDIT_TOKEN_BINARY, buffer);
+  return item;
+}
+
diff --git a/test/swfedit_tag.h b/test/swfedit_tag.h
new file mode 100644
index 0000000..aad879e
--- /dev/null
+++ b/test/swfedit_tag.h
@@ -0,0 +1,56 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_TAG_H__
+#define __SWFEDIT_TAG_H__
+
+#include <libswfdec/swfdec_buffer.h>
+#include "swfedit_token.h"
+
+G_BEGIN_DECLS
+
+typedef struct _SwfeditTag SwfeditTag;
+typedef struct _SwfeditTagClass SwfeditTagClass;
+
+#define SWFEDIT_TYPE_TAG                    (swfedit_tag_get_type())
+#define SWFEDIT_IS_TAG(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TAG))
+#define SWFEDIT_IS_TAG_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TAG))
+#define SWFEDIT_TAG(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TAG, SwfeditTag))
+#define SWFEDIT_TAG_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TAG, SwfeditTagClass))
+#define SWFEDIT_TAG_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TAG, SwfeditTagClass))
+
+struct _SwfeditTag {
+  SwfeditToken		token;
+
+  guint			tag;		/* tag type */
+};
+
+struct _SwfeditTagClass {
+  SwfeditTokenClass	token_class;
+};
+
+GType		swfedit_tag_get_type	(void);
+
+SwfeditTag *	swfedit_tag_new		(guint		tag,
+					 SwfdecBuffer *	buffer);
+
+
+G_END_DECLS
+
+#endif
diff --git a/test/swfedit_token.c b/test/swfedit_token.c
new file mode 100644
index 0000000..78951f2
--- /dev/null
+++ b/test/swfedit_token.c
@@ -0,0 +1,464 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <libswfdec/swfdec_buffer.h>
+#include "swfedit_token.h"
+
+/*** CONVERTERS ***/
+
+static gboolean
+swfedit_binary_read (const char *s, gpointer* result)
+{
+  GByteArray *array = g_byte_array_new ();
+  guint8 byte;
+
+  while (g_ascii_isspace (*s)) s++;
+  do {
+    if (s[0] >= '0' && s[0] <= '9')
+      byte = s[0] - '0';
+    else if (s[0] >= 'a' && s[0] <= 'f')
+      byte = s[0] + 10 - 'a';
+    else if (s[0] >= 'A' && s[0] <= 'F')
+      byte = s[0] + 10 - 'A';
+    else
+      break;
+    s++;
+    byte *= 255;
+    if (s[0] >= '0' && s[0] <= '9')
+      byte = s[0] - '0';
+    else if (s[0] >= 'a' && s[0] <= 'f')
+      byte = s[0] + 10 - 'a';
+    else if (s[0] >= 'A' && s[0] <= 'F')
+      byte = s[0] + 10 - 'A';
+    else
+      break;
+    s++;
+    g_byte_array_append (array, &byte, 1);
+    while (g_ascii_isspace (*s)) s++;
+  } while (TRUE);
+  if (*s == '\0') {
+    SwfdecBuffer *buffer = swfdec_buffer_new ();
+    buffer->length = array->len;
+    buffer->data = array->data;
+    g_byte_array_free (array, FALSE);
+    *result = buffer;
+    return TRUE;
+  }
+  g_byte_array_free (array, TRUE);
+  return FALSE;
+}
+
+static char *
+swfedit_binary_write (gconstpointer value)
+{
+  guint i;
+  const SwfdecBuffer *buffer = value;
+  GString *string = g_string_new ("");
+
+  for (i = 0; i < buffer->length; i++) {
+    if (i && i % 4 == 0)
+      g_string_append_c (string, ' ');
+    g_string_append_printf (string, "%2X", buffer->data[i]);
+  }
+  return g_string_free (string, FALSE);
+}
+
+static gboolean
+swfedit_read_unsigned (const char *s, gulong max, gpointer* result)
+{
+  char *end;
+  gulong u;
+
+  g_assert (max <= G_MAXUINT);
+  u = strtoul (s, &end, 10);
+  if (*end != '\0')
+    return FALSE;
+  if (u > max)
+    return FALSE;
+  *result = GUINT_TO_POINTER ((guint) u);
+  return TRUE;
+}
+
+static gboolean
+swfedit_uint8_read (const char *s, gpointer* result)
+{
+  return swfedit_read_unsigned (s, G_MAXUINT8, result);
+}
+
+static gboolean
+swfedit_uint16_read (const char *s, gpointer* result)
+{
+  return swfedit_read_unsigned (s, G_MAXUINT16, result);
+}
+
+static gboolean
+swfedit_uint32_read (const char *s, gpointer* result)
+{
+  return swfedit_read_unsigned (s, G_MAXUINT32, result);
+}
+
+static char *
+swfedit_write_unsigned (gconstpointer value)
+{
+  return g_strdup_printf ("%u", GPOINTER_TO_UINT (value));
+}
+
+struct {
+  gboolean	(* read)	(const char *s, gpointer *);
+  char *	(* write)	(gconstpointer value);
+  void	  	(* free)	(gpointer value);
+} converters[SWFEDIT_N_TOKENS] = {
+  { NULL, NULL, g_object_unref },
+  { swfedit_binary_read, swfedit_binary_write, (GDestroyNotify) swfdec_buffer_unref },
+  { swfedit_uint8_read, swfedit_write_unsigned, NULL },
+  { swfedit_uint16_read, swfedit_write_unsigned, NULL },
+  { swfedit_uint32_read, swfedit_write_unsigned, NULL },
+};
+
+/*** STRUCTS ***/
+
+typedef struct {
+  char *		name;
+  SwfeditTokenType	type;
+  gpointer		value;
+} Entry;
+
+/*** GTK_TREE_MODEL ***/
+
+static GtkTreeModelFlags 
+swfedit_token_get_flags (GtkTreeModel *tree_model)
+{
+  return 0;
+}
+
+static gint
+swfedit_token_get_n_columns (GtkTreeModel *tree_model)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (tree_model);
+
+  return token->tokens->len;
+}
+
+static GType
+swfedit_token_get_column_type (GtkTreeModel *tree_model, gint index_)
+{
+  switch (index_) {
+    case SWFEDIT_COLUMN_NAME:
+      return G_TYPE_STRING;
+    case SWFEDIT_COLUMN_VALUE_VISIBLE:
+      return G_TYPE_BOOLEAN;
+    case SWFEDIT_COLUMN_VALUE:
+      return G_TYPE_STRING;
+    default:
+      break;
+  }
+  g_assert_not_reached ();
+  return G_TYPE_NONE;
+}
+
+static gboolean
+swfedit_token_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (tree_model);
+  guint i = gtk_tree_path_get_indices (path)[0];
+  Entry *entry;
+  
+  if (i > token->tokens->len)
+    return FALSE;
+  entry = &g_array_index (token->tokens, Entry, i);
+  if (gtk_tree_path_get_depth (path) > 1) {
+    GtkTreePath *new;
+    int j;
+    int *indices;
+    gboolean ret;
+
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      return FALSE;
+    new = gtk_tree_path_new ();
+    indices = gtk_tree_path_get_indices (path);
+    for (j = 1; j < gtk_tree_path_get_depth (path); j++) {
+      gtk_tree_path_append_index (path, indices[j]);
+    }
+    ret = swfedit_token_get_iter (GTK_TREE_MODEL (entry->value), iter, new);
+    gtk_tree_path_free (new);
+    return ret;
+  } else {
+    iter->stamp = 0; /* FIXME */
+    iter->user_data = token;
+    iter->user_data2 = GINT_TO_POINTER (i);
+    return TRUE;
+  }
+}
+
+static GtkTreePath *
+swfedit_token_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data2), -1);
+
+  while (token->parent) {
+    guint i;
+    SwfeditToken *parent = token->parent;
+    for (i = 0; i < parent->tokens->len; i++) {
+      Entry *entry = &g_array_index (parent->tokens, Entry, i);
+      if (entry->type != SWFEDIT_TOKEN_OBJECT)
+	continue;
+      if (entry->value == token)
+	break;
+    }
+    gtk_tree_path_prepend_index (path, i);
+    token = parent;
+  }
+  return path;
+}
+
+static void 
+swfedit_token_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter,
+    gint column, GValue *value)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2));
+
+  switch (column) {
+    case SWFEDIT_COLUMN_NAME:
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_string (value, entry->name);
+      return;
+    case SWFEDIT_COLUMN_VALUE_VISIBLE:
+      g_value_init (value, G_TYPE_BOOLEAN);
+      g_value_set_boolean (value, converters[entry->type].write != NULL);
+      return;
+    case SWFEDIT_COLUMN_VALUE:
+      g_value_init (value, G_TYPE_STRING);
+      if (converters[entry->type].write)
+	g_value_take_string (value, converters[entry->type].write (entry->value));
+      return;
+    default:
+      break;
+  }
+  g_assert_not_reached ();
+}
+
+static gboolean
+swfedit_token_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+
+  if ((guint) GPOINTER_TO_INT (iter->user_data2) + 1 >= token->tokens->len)
+    return FALSE;
+
+  iter->user_data2++;
+  return TRUE;
+}
+
+static gboolean
+swfedit_token_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (parent->user_data);
+  Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2));
+
+  if (entry->type != SWFEDIT_TOKEN_OBJECT)
+    return FALSE;
+
+  iter->stamp = 0; /* FIXME */
+  iter->user_data = entry->value;
+  iter->user_data2 = GINT_TO_POINTER (0);
+  return TRUE;
+}
+
+static gboolean
+swfedit_token_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2));
+
+  return entry->type == SWFEDIT_TOKEN_OBJECT;
+}
+
+static gint
+swfedit_token_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (iter->user_data);
+  Entry *entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (iter->user_data2));
+
+  if (entry->type != SWFEDIT_TOKEN_OBJECT)
+    return FALSE;
+
+  token = entry->value;
+  return token->tokens->len;
+}
+
+static gboolean
+swfedit_token_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter,
+    GtkTreeIter *parent, gint n)
+{
+  SwfeditToken *token;
+  Entry *entry;
+
+  if (parent) {
+    token = SWFEDIT_TOKEN (parent->user_data);
+    entry = &g_array_index (token->tokens, Entry, GPOINTER_TO_INT (parent->user_data2));
+
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      return FALSE;
+
+    token = entry->value;
+    if ((guint) n >= token->tokens->len)
+      return FALSE;
+  }
+  iter->stamp = 0; /* FIXME */
+  iter->user_data = token;
+  iter->user_data2 = GINT_TO_POINTER (n);
+  return TRUE;
+}
+
+static gboolean
+swfedit_token_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
+{
+  guint i;
+  SwfeditToken *token = SWFEDIT_TOKEN (child->user_data);
+  SwfeditToken *parent = token->parent;
+
+  if (parent == NULL)
+    return FALSE;
+
+  for (i = 0; i < parent->tokens->len; i++) {
+    Entry *entry = &g_array_index (parent->tokens, Entry, i);
+    if (entry->type != SWFEDIT_TOKEN_OBJECT)
+      continue;
+    if (entry->value == token)
+      break;
+  }
+  iter->stamp = 0; /* FIXME */
+  iter->user_data = token;
+  iter->user_data2 = GINT_TO_POINTER (i);
+  return TRUE;
+}
+
+static void
+swfedit_token_tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags = swfedit_token_get_flags;
+  iface->get_n_columns = swfedit_token_get_n_columns;
+  iface->get_column_type = swfedit_token_get_column_type;
+  iface->get_iter = swfedit_token_get_iter;
+  iface->get_path = swfedit_token_get_path;
+  iface->get_value = swfedit_token_get_value;
+  iface->iter_next = swfedit_token_iter_next;
+  iface->iter_children = swfedit_token_iter_children;
+  iface->iter_has_child = swfedit_token_iter_has_child;
+  iface->iter_n_children = swfedit_token_iter_n_children;
+  iface->iter_nth_child = swfedit_token_iter_nth_child;
+  iface->iter_parent = swfedit_token_iter_parent;
+}
+
+/*** SWFEDIT_TOKEN ***/
+
+G_DEFINE_TYPE_WITH_CODE (SwfeditToken, swfedit_token, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, swfedit_token_tree_model_init))
+
+static void
+swfedit_token_dispose (GObject *object)
+{
+  SwfeditToken *token = SWFEDIT_TOKEN (object);
+  guint i;
+
+  for (i = 0; i < token->tokens->len; i++) {
+    Entry *entry = &g_array_index (token->tokens, Entry, i);
+    g_free (entry->name);
+    if (converters[entry->type].free)
+      converters[entry->type].free (entry->value);
+  }
+  g_array_free (token->tokens, TRUE);
+
+  G_OBJECT_CLASS (swfedit_token_parent_class)->dispose (object);
+}
+
+static void
+swfedit_token_class_init (SwfeditTokenClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->dispose = swfedit_token_dispose;
+}
+
+static void
+swfedit_token_init (SwfeditToken *token)
+{
+  token->tokens = g_array_new (FALSE, FALSE, sizeof (Entry));
+}
+
+SwfeditToken *
+swfedit_token_new (void)
+{
+  SwfeditToken *token;
+
+  token = g_object_new (SWFEDIT_TYPE_TOKEN, NULL);
+  return token;
+}
+
+void
+swfedit_token_add (SwfeditToken *token, const char *name, SwfeditTokenType type, gpointer value)
+{
+  Entry entry = { NULL, type, value };
+
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (name != NULL);
+  g_return_if_fail (type < SWFEDIT_N_TOKENS);
+
+  entry.name = g_strdup (name);
+  g_array_append_val (token->tokens, entry);
+}
+
+void
+swfedit_token_set (SwfeditToken *token, GtkTreeIter *iter, const char *value)
+{
+  GtkTreeModel *model;
+  Entry *entry;
+  guint i;
+  gpointer new;
+  GtkTreePath *path;
+
+  g_return_if_fail (SWFEDIT_IS_TOKEN (token));
+  g_return_if_fail (iter != NULL);
+  g_return_if_fail (value != NULL);
+
+  model = GTK_TREE_MODEL (token);
+  token = iter->user_data;
+  i = GPOINTER_TO_UINT (iter->user_data2);
+  entry = &g_array_index (token->tokens, Entry, i);
+  if (converters[entry->type].read == NULL)
+    return;
+  if (!converters[entry->type].read (value, &new))
+    return;
+  if (converters[entry->type].free != NULL)
+    converters[entry->type].free (entry->value);
+  entry->value = new;
+
+  path = gtk_tree_model_get_path (model, iter);
+  gtk_tree_model_row_changed (model, path, iter);
+  gtk_tree_path_free (path);
+}
+
diff --git a/test/swfedit_token.h b/test/swfedit_token.h
new file mode 100644
index 0000000..1640027
--- /dev/null
+++ b/test/swfedit_token.h
@@ -0,0 +1,79 @@
+/* Swfedit
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __SWFEDIT_TOKEN_H__
+#define __SWFEDIT_TOKEN_H__
+
+#include <gtk/gtk.h>
+#include <libswfdec/swfdec_rect.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  SWFEDIT_TOKEN_OBJECT,
+  SWFEDIT_TOKEN_BINARY,
+  SWFEDIT_TOKEN_UINT8,
+  SWFEDIT_TOKEN_UINT16,
+  SWFEDIT_TOKEN_UINT32,
+  SWFEDIT_N_TOKENS
+} SwfeditTokenType;
+
+typedef enum {
+  SWFEDIT_COLUMN_NAME,
+  SWFEDIT_COLUMN_VALUE_VISIBLE,
+  SWFEDIT_COLUMN_VALUE
+} SwfeditColumn;
+
+typedef struct _SwfeditToken SwfeditToken;
+typedef struct _SwfeditTokenClass SwfeditTokenClass;
+
+#define SWFEDIT_TYPE_TOKEN                    (swfedit_token_get_type())
+#define SWFEDIT_IS_TOKEN(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFEDIT_TYPE_TOKEN))
+#define SWFEDIT_IS_TOKEN_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFEDIT_TYPE_TOKEN))
+#define SWFEDIT_TOKEN(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFEDIT_TYPE_TOKEN, SwfeditToken))
+#define SWFEDIT_TOKEN_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass))
+#define SWFEDIT_TOKEN_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFEDIT_TYPE_TOKEN, SwfeditTokenClass))
+
+struct _SwfeditToken {
+  GObject		object;
+
+  SwfeditToken *	parent;		/* parent of this token or NULL */
+  gchar *		name;		/* name of token */
+  GArray *		tokens;		/* list of tokens */
+};
+
+struct _SwfeditTokenClass {
+  GObjectClass		object_class;
+};
+
+GType		swfedit_token_get_type		(void);
+
+SwfeditToken *	swfedit_token_new		(void);
+void		swfedit_token_add		(SwfeditToken *		token,
+						 const char *		name,
+						 SwfeditTokenType	type,
+						 gpointer		value);
+void		swfedit_token_set		(SwfeditToken *		token,
+						 GtkTreeIter *		iter,
+						 const char *		value);
+
+
+G_END_DECLS
+
+#endif
diff-tree ac526c14b6a853304588e1c71ccc0ab709ac072e (from 134ac8ae16f9e1cf5dc68f4ebb97bba74bed0235)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 22 18:32:04 2007 +0100

    convert the parsing code to the recent SwfdecBits API

diff --git a/libswfdec/swfdec_swf_decoder.c b/libswfdec/swfdec_swf_decoder.c
index a43c9ac..6539921 100644
--- a/libswfdec/swfdec_swf_decoder.c
+++ b/libswfdec/swfdec_swf_decoder.c
@@ -206,10 +206,7 @@ swf_parse_header2 (SwfdecSwfDecoder * s)
     return SWFDEC_STATUS_NEEDBITS;
   }
 
-  s->b.buffer = buffer;
-  s->b.ptr = buffer->data;
-  s->b.idx = 0;
-  s->b.end = buffer->data + buffer->length;
+  swfdec_bits_init (&s->b, buffer);
 
   swfdec_bits_get_rect (&s->b, &rect);
   if (rect.x0 != 0.0 || rect.y0 != 0.0)
@@ -239,7 +236,6 @@ swfdec_swf_decoder_parse (SwfdecDecoder 
 {
   SwfdecSwfDecoder *s = SWFDEC_SWF_DECODER (dec);
   int ret = SWFDEC_STATUS_OK;
-  const unsigned char *endptr;
   SwfdecBuffer *buffer;
 
   s->b = s->parse;
@@ -271,12 +267,7 @@ swfdec_swf_decoder_parse (SwfdecDecoder 
       if (buffer == NULL) {
 	return SWFDEC_STATUS_NEEDBITS;
       }
-
-      s->b.buffer = buffer;
-      s->b.ptr = buffer->data;
-      s->b.idx = 0;
-      s->b.end = buffer->data + buffer->length;
-
+      swfdec_bits_init (&s->b, buffer);
 
       x = swfdec_bits_get_u16 (&s->b);
       tag = (x >> 6) & 0x3ff;
@@ -288,10 +279,7 @@ swfdec_swf_decoder_parse (SwfdecDecoder 
 	if (buffer == NULL) {
 	  return SWFDEC_STATUS_NEEDBITS;
 	}
-	s->b.buffer = buffer;
-	s->b.ptr = buffer->data;
-	s->b.idx = 0;
-	s->b.end = buffer->data + buffer->length;
+	swfdec_bits_init (&s->b, buffer);
 
 	swfdec_bits_get_u16 (&s->b);
 	tag_len = swfdec_bits_get_u32 (&s->b);
@@ -313,21 +301,11 @@ swfdec_swf_decoder_parse (SwfdecDecoder 
       buffer = swfdec_buffer_queue_pull (s->input_queue, header_length);
       swfdec_buffer_unref (buffer);
 
-      if (tag_len > 0) {
+      if (tag_len > 0)
 	buffer = swfdec_buffer_queue_pull (s->input_queue, tag_len);
-	s->b.buffer = buffer;
-	s->b.ptr = buffer->data;
-	s->b.idx = 0;
-	s->b.end = buffer->data + buffer->length;
-	endptr = s->b.ptr + tag_len;
-      } else {
+      else
 	buffer = NULL;
-	s->b.buffer = NULL;
-	s->b.ptr = NULL;
-	s->b.idx = 0;
-	s->b.end = NULL;
-	endptr = NULL;
-      }
+      swfdec_bits_init (&s->b, buffer);
       func = swfdec_swf_decoder_get_tag_func (tag);
       if (func == NULL) {
 	SWFDEC_WARNING ("tag function not implemented for %d %s",
@@ -338,18 +316,10 @@ swfdec_swf_decoder_parse (SwfdecDecoder 
 	s->parse_sprite = NULL;
 
 	swfdec_bits_syncbits (&s->b);
-	if (s->b.ptr < endptr) {
+	if (swfdec_bits_left (&s->b)) {
 	  SWFDEC_WARNING
 	      ("early finish (%d bytes) at %d, tag %d %s, length %d",
-	      endptr - s->b.ptr,
-	      swfdec_buffer_queue_get_offset (s->input_queue), tag,
-	      swfdec_swf_decoder_get_tag_name (tag), tag_len);
-	  //dumpbits (&s->b);
-	}
-	if (s->b.ptr > endptr) {
-	  SWFDEC_WARNING
-	      ("parse_overrun (%d bytes) at %d, tag %d %s, length %d",
-	      s->b.ptr - endptr,
+	      swfdec_bits_left (&s->b) / 8,
 	      swfdec_buffer_queue_get_offset (s->input_queue), tag,
 	      swfdec_swf_decoder_get_tag_name (tag), tag_len);
 	}
diff-tree 134ac8ae16f9e1cf5dc68f4ebb97bba74bed0235 (from 878ec656b0711cd19c11554d0617109a058af799)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 22 18:17:48 2007 +0100

    allow NULL buffer in swfdec_bits_init and 0 length in swfdec_bits_get_buffer
    
    This simplifies error checking, since we catch errors in those cases anyway:
    - NULL buffer bits are like data bits that finished reading
    - 0 length get_buffer returns NULL, which is a valid return value for the error case

diff --git a/libswfdec/swfdec_bits.c b/libswfdec/swfdec_bits.c
index 72cc3df..1a7e402 100644
--- a/libswfdec/swfdec_bits.c
+++ b/libswfdec/swfdec_bits.c
@@ -31,16 +31,27 @@
 #include "swfdec_rect.h"
 
 
+/**
+ * swfdec_bits_init:
+ * @bits: a #SwfdecBits
+ * @buffer: buffer to use for data or NULL
+ *
+ * initializes @bits for use with the data in @buffer. The buffer will not be
+ * referenced, so you are responsible for keeping it around while @bits is used.
+ **/
 void 
 swfdec_bits_init (SwfdecBits *bits, SwfdecBuffer *buffer)
 {
   g_return_if_fail (bits != NULL);
-  g_return_if_fail (buffer != NULL);
 
-  bits->buffer = buffer;
-  bits->ptr = buffer->data;
-  bits->idx = 0;
-  bits->end = buffer->data + buffer->length;
+  if (buffer) {
+    bits->buffer = buffer;
+    bits->ptr = buffer->data;
+    bits->idx = 0;
+    bits->end = buffer->data + buffer->length;
+  } else {
+    memset (bits, 0, sizeof (SwfdecBits));
+  }
 }
 
 /**
@@ -567,7 +578,7 @@ swfdec_bits_get_buffer (SwfdecBits *bits
 {
   SwfdecBuffer *buffer;
 
-  g_return_val_if_fail (len > 0 || len == -1, NULL);
+  g_return_val_if_fail (len >= -1, NULL);
 
   if (len > 0) {
     SWFDEC_BYTES_CHECK (bits, (unsigned int) len);
@@ -575,9 +586,9 @@ swfdec_bits_get_buffer (SwfdecBits *bits
     swfdec_bits_syncbits (bits);
     len = bits->end - bits->ptr;
     g_assert (len >= 0);
-    if (len == 0)
-      return NULL;
   }
+  if (len == 0)
+    return NULL;
   if (bits->buffer) {
     buffer = swfdec_buffer_new_subbuffer (bits->buffer, bits->ptr - bits->buffer->data, len);
   } else {


More information about the Swfdec mailing list