[Swfdec-commits] 101 commits - configure.ac swfdec/swfdec_as_interpret.c swfdec/swfdec_as_interpret.h swfdec/swfdec_script.c swfdec/swfdec_script.h swfdec/swfdec_script_internal.h vivified/code vivified/Makefile.am

Benjamin Otte company at kemper.freedesktop.org
Wed Mar 26 05:30:05 PDT 2008


 configure.ac                              |    2 
 swfdec/swfdec_as_interpret.c              |    8 
 swfdec/swfdec_as_interpret.h              |    1 
 swfdec/swfdec_script.c                    |    8 
 swfdec/swfdec_script.h                    |    1 
 swfdec/swfdec_script_internal.h           |   18 
 vivified/Makefile.am                      |    2 
 vivified/code/.gitignore                  |   14 
 vivified/code/Makefile.am                 |   79 +
 vivified/code/decompiler.c                |   87 +
 vivified/code/test/Makefile.am            |   35 
 vivified/code/test/and-or.as              |   16 
 vivified/code/test/and-or.swf             |binary
 vivified/code/test/and-or.swf.expect      |   18 
 vivified/code/test/hello-world.as         |    5 
 vivified/code/test/hello-world.swf        |binary
 vivified/code/test/hello-world.swf.expect |    8 
 vivified/code/test/if-nested.as           |   15 
 vivified/code/test/if-nested.swf          |binary
 vivified/code/test/if-nested.swf.expect   |   17 
 vivified/code/test/if.as                  |   17 
 vivified/code/test/if.swf                 |binary
 vivified/code/test/if.swf.expect          |   15 
 vivified/code/test/loop-nested.as         |    5 
 vivified/code/test/loop-nested.swf        |binary
 vivified/code/test/loop-nested.swf.expect |    9 
 vivified/code/test/simple-loop.as         |    5 
 vivified/code/test/simple-loop.swf        |binary
 vivified/code/test/simple-loop.swf.expect |    8 
 vivified/code/vivi_code_assignment.c      |  131 ++
 vivified/code/vivi_code_assignment.h      |   63 +
 vivified/code/vivi_code_binary.c          |  165 +++
 vivified/code/vivi_code_binary.h          |   62 +
 vivified/code/vivi_code_block.c           |  164 +++
 vivified/code/vivi_code_block.h           |   66 +
 vivified/code/vivi_code_break.c           |   54 +
 vivified/code/vivi_code_break.h           |   54 +
 vivified/code/vivi_code_comment.c         |   78 +
 vivified/code/vivi_code_comment.h         |   56 +
 vivified/code/vivi_code_constant.c        |  237 ++++
 vivified/code/vivi_code_constant.h        |   66 +
 vivified/code/vivi_code_continue.c        |   54 +
 vivified/code/vivi_code_continue.h        |   54 +
 vivified/code/vivi_code_function.c        |  108 ++
 vivified/code/vivi_code_function.h        |   58 +
 vivified/code/vivi_code_function_call.c   |  177 +++
 vivified/code/vivi_code_function_call.h   |   61 +
 vivified/code/vivi_code_get.c             |  130 ++
 vivified/code/vivi_code_get.h             |   59 +
 vivified/code/vivi_code_get_url.c         |   98 +
 vivified/code/vivi_code_get_url.h         |   65 +
 vivified/code/vivi_code_goto.c            |   78 +
 vivified/code/vivi_code_goto.h            |   57 +
 vivified/code/vivi_code_if.c              |  185 +++
 vivified/code/vivi_code_if.h              |   63 +
 vivified/code/vivi_code_label.c           |   86 +
 vivified/code/vivi_code_label.h           |   58 +
 vivified/code/vivi_code_loop.c            |  120 ++
 vivified/code/vivi_code_loop.h            |   62 +
 vivified/code/vivi_code_printer.c         |  133 ++
 vivified/code/vivi_code_printer.h         |   82 +
 vivified/code/vivi_code_return.c          |   90 +
 vivified/code/vivi_code_return.h          |   60 +
 vivified/code/vivi_code_statement.c       |   79 +
 vivified/code/vivi_code_statement.h       |   57 +
 vivified/code/vivi_code_text_printer.c    |   80 +
 vivified/code/vivi_code_text_printer.h    |   56 +
 vivified/code/vivi_code_token.c           |   48 
 vivified/code/vivi_code_token.h           |   57 +
 vivified/code/vivi_code_trace.c           |   78 +
 vivified/code/vivi_code_trace.h           |   57 +
 vivified/code/vivi_code_unary.c           |  119 ++
 vivified/code/vivi_code_unary.h           |   59 +
 vivified/code/vivi_code_value.c           |  103 ++
 vivified/code/vivi_code_value.h           |   93 +
 vivified/code/vivi_code_value_statement.c |   85 +
 vivified/code/vivi_code_value_statement.h |   59 +
 vivified/code/vivi_decompiler.c           | 1508 ++++++++++++++++++++++++++++++
 vivified/code/vivi_decompiler.h           |   33 
 vivified/code/vivi_decompiler_block.c     |  402 +++++++
 vivified/code/vivi_decompiler_block.h     |  106 ++
 vivified/code/vivi_decompiler_duplicate.c |   95 +
 vivified/code/vivi_decompiler_duplicate.h |   58 +
 vivified/code/vivi_decompiler_state.c     |  218 ++++
 vivified/code/vivi_decompiler_state.h     |   71 +
 vivified/code/vivi_decompiler_unknown.c   |  151 +++
 vivified/code/vivi_decompiler_unknown.h   |   66 +
 vivified/code/vivified-compiler.h         |   25 
 88 files changed, 7276 insertions(+), 14 deletions(-)

New commits:
commit 58f0c32ac572af6387f763918a474883b1e36cbb
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 13:21:52 2008 +0100

    use the right number of registers

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 6143121..de7657f 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -1480,7 +1480,7 @@ vivi_decompile_script (SwfdecScript *script)
   g_return_val_if_fail (script != NULL, NULL);
 
   DEBUG ("--> starting decompilation\n");
-  state = vivi_decompiler_state_new (script, script->main, 4);
+  state = vivi_decompiler_state_new (script, script->main, script->n_registers);
   vivi_decompiler_preload (state, script);
   if (script->constant_pool) {
     vivi_decompiler_state_set_constant_pool (state,
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index 0cdd743..f821f26 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -137,8 +137,10 @@ vivi_decompiler_state_set_register (ViviDecompilerState *state, guint reg,
   g_return_if_fail (state != NULL);
   g_return_if_fail (VIVI_IS_CODE_VALUE (value));
 
-  if (reg >= state->n_registers)
+  if (reg >= state->n_registers) {
+    g_printerr ("register %u out of range [0,%u]\n", reg, state->n_registers);
     return;
+  }
 
   if (state->registers[reg] != NULL)
     g_object_unref (state->registers[reg]);
commit 45edd28fcd8cd01ba33ca8d92334b492b0df95ce
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 12:51:56 2008 +0100

    redo handling of return statements.
    
    We now add a return statemenet explicitly when we finish a block.
    Also adds decompilation of return bytecode.

diff --git a/vivified/code/vivi_code_return.c b/vivified/code/vivi_code_return.c
index 53fcfcc..1afe780 100644
--- a/vivified/code/vivi_code_return.c
+++ b/vivified/code/vivi_code_return.c
@@ -69,7 +69,7 @@ vivi_code_return_init (ViviCodeReturn *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_return_new (void)
 {
   return g_object_new (VIVI_TYPE_CODE_RETURN, NULL);
diff --git a/vivified/code/vivi_code_return.h b/vivified/code/vivi_code_return.h
index 3e9faf6..330ffbe 100644
--- a/vivified/code/vivi_code_return.h
+++ b/vivified/code/vivi_code_return.h
@@ -50,7 +50,7 @@ struct _ViviCodeReturnClass
 
 GType			vivi_code_return_get_type   	(void);
 
-ViviCodeToken *		vivi_code_return_new		(void);
+ViviCodeStatement *   	vivi_code_return_new		(void);
 
 void			vivi_code_return_set_value	(ViviCodeReturn *	ret,
 							 ViviCodeValue *	value);
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index fc810dd..6143121 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -244,6 +244,32 @@ static gboolean
 vivi_decompile_end (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
+  ViviCodeStatement *ret;
+
+  ret = vivi_code_return_new ();
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), ret);
+  g_object_unref (ret);
+
+  vivi_decompiler_block_finish (block, state);
+  return FALSE;
+}
+
+static gboolean
+vivi_decompile_return (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeStatement *ret;
+  ViviCodeValue *value;
+
+  value = vivi_decompiler_state_pop (state);
+  ret = vivi_code_return_new ();
+  if (!VIVI_IS_CODE_CONSTANT (value) ||
+      vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (value)) != SWFDEC_AS_TYPE_UNDEFINED)
+    vivi_code_return_set_value (VIVI_CODE_RETURN (ret), value);
+  g_object_unref (value);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), ret);
+  g_object_unref (ret);
+
   vivi_decompiler_block_finish (block, state);
   return FALSE;
 }
@@ -629,7 +655,7 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_DELETE2] = NULL,
   [SWFDEC_AS_ACTION_DEFINE_LOCAL] = NULL,
   [SWFDEC_AS_ACTION_CALL_FUNCTION] = vivi_decompile_call_function,
-  [SWFDEC_AS_ACTION_RETURN] = NULL,
+  [SWFDEC_AS_ACTION_RETURN] = vivi_decompile_return,
   [SWFDEC_AS_ACTION_MODULO] = NULL,
   [SWFDEC_AS_ACTION_NEW_OBJECT] = NULL,
   [SWFDEC_AS_ACTION_DEFINE_LOCAL2] = NULL,
@@ -747,16 +773,16 @@ vivi_decompiler_process (GList **blocks, ViviDecompilerBlock *block,
       }
       return FALSE;
     default:
+      if (data)
+	vivi_decompiler_state_add_pc (state, 3 + len);
+      else
+	vivi_decompiler_state_add_pc (state, 1);
       if (decompile_funcs[code]) {
 	result = decompile_funcs[code] (block, state, code, data, len);
       } else {
 	vivi_decompiler_block_add_warning (block, "unknown bytecode 0x%02X %u", code, code);
 	result = TRUE;
       }
-      if (data)
-	vivi_decompiler_state_add_pc (state, 3 + len);
-      else
-	vivi_decompiler_state_add_pc (state, 1);
       return result;
   };
 
@@ -814,6 +840,12 @@ vivi_decompiler_block_decompile (GList *blocks, ViviDecompilerBlock *block, Swfd
     vivi_decompiler_block_set_next (block,
 	vivi_decompiler_push_block_for_state (&blocks, state));
   } else {
+    ViviCodeStatement *ret;
+
+    ret = vivi_code_return_new ();
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), ret);
+    g_object_unref (ret);
+
 out:
 error:
     vivi_decompiler_state_free (state);
@@ -887,8 +919,6 @@ vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
     } else {
       vivi_decompiler_block_add_to_block (current, block);
     }
-    if (next == NULL && walk->next != NULL)
-      vivi_code_block_add_statement (block, VIVI_CODE_STATEMENT (vivi_code_return_new ()));
     vivi_decompiler_block_set_next (current, NULL);
     vivi_decompiler_block_set_branch (current, NULL, NULL);
   }
commit de63b3611127e789c0ccd92fc10e0ec155585136
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 12:38:13 2008 +0100

    add NULL vfuncs for missing bytecodes

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 4c63753..fc810dd 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -582,11 +582,12 @@ vivi_decompile_store_register (ViviDecompilerBlock *block, ViviDecompilerState *
 
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
-  [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
-  [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
-  [SWFDEC_AS_ACTION_GET_VARIABLE] = vivi_decompile_get_variable,
-  [SWFDEC_AS_ACTION_SET_VARIABLE] = vivi_decompile_set_variable,
-  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
+  [SWFDEC_AS_ACTION_NEXT_FRAME] = NULL,
+  [SWFDEC_AS_ACTION_PREVIOUS_FRAME] = NULL,
+  [SWFDEC_AS_ACTION_PLAY] = NULL,
+  [SWFDEC_AS_ACTION_STOP] = NULL,
+  [SWFDEC_AS_ACTION_TOGGLE_QUALITY] = NULL,
+  [SWFDEC_AS_ACTION_STOP_SOUNDS] = NULL,
   [SWFDEC_AS_ACTION_ADD] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_SUBTRACT] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_MULTIPLY] = vivi_decompile_binary,
@@ -595,16 +596,64 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_LESS] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_AND] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_OR] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
   [SWFDEC_AS_ACTION_STRING_EQUALS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_STRING_LENGTH] = NULL,
+  [SWFDEC_AS_ACTION_STRING_EXTRACT] = NULL,
+  [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
+  [SWFDEC_AS_ACTION_TO_INTEGER] = NULL,
+  [SWFDEC_AS_ACTION_GET_VARIABLE] = vivi_decompile_get_variable,
+  [SWFDEC_AS_ACTION_SET_VARIABLE] = vivi_decompile_set_variable,
+  [SWFDEC_AS_ACTION_SET_TARGET2] = NULL,
+  [SWFDEC_AS_ACTION_STRING_ADD] = NULL,
+  [SWFDEC_AS_ACTION_GET_PROPERTY] = NULL,
+  [SWFDEC_AS_ACTION_SET_PROPERTY] = NULL,
+  [SWFDEC_AS_ACTION_CLONE_SPRITE] = NULL,
+  [SWFDEC_AS_ACTION_REMOVE_SPRITE] = NULL,
+  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
+  [SWFDEC_AS_ACTION_START_DRAG] = NULL,
+  [SWFDEC_AS_ACTION_END_DRAG] = NULL,
   [SWFDEC_AS_ACTION_STRING_LESS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_THROW] = NULL,
+  [SWFDEC_AS_ACTION_CAST] = NULL,
+  [SWFDEC_AS_ACTION_IMPLEMENTS] = NULL,
+  [SWFDEC_AS_ACTION_RANDOM] = NULL,
+  [SWFDEC_AS_ACTION_MB_STRING_LENGTH] = NULL,
+  [SWFDEC_AS_ACTION_CHAR_TO_ASCII] = NULL,
+  [SWFDEC_AS_ACTION_ASCII_TO_CHAR] = NULL,
+  [SWFDEC_AS_ACTION_GET_TIME] = NULL,
+  [SWFDEC_AS_ACTION_MB_STRING_EXTRACT] = NULL,
+  [SWFDEC_AS_ACTION_MB_CHAR_TO_ASCII] = NULL,
+  [SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR] = NULL,
+  [SWFDEC_AS_ACTION_DELETE] = NULL,
+  [SWFDEC_AS_ACTION_DELETE2] = NULL,
+  [SWFDEC_AS_ACTION_DEFINE_LOCAL] = NULL,
   [SWFDEC_AS_ACTION_CALL_FUNCTION] = vivi_decompile_call_function,
+  [SWFDEC_AS_ACTION_RETURN] = NULL,
+  [SWFDEC_AS_ACTION_MODULO] = NULL,
+  [SWFDEC_AS_ACTION_NEW_OBJECT] = NULL,
+  [SWFDEC_AS_ACTION_DEFINE_LOCAL2] = NULL,
+  [SWFDEC_AS_ACTION_INIT_ARRAY] = NULL,
+  [SWFDEC_AS_ACTION_INIT_OBJECT] = NULL,
+  [SWFDEC_AS_ACTION_TYPE_OF] = NULL,
+  [SWFDEC_AS_ACTION_TARGET_PATH] = NULL,
+  [SWFDEC_AS_ACTION_ENUMERATE] = NULL,
   [SWFDEC_AS_ACTION_ADD2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_LESS2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_EQUALS2] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_TO_NUMBER] = NULL,
+  [SWFDEC_AS_ACTION_TO_STRING] = NULL,
   [SWFDEC_AS_ACTION_PUSH_DUPLICATE] = vivi_decompile_duplicate,
+  [SWFDEC_AS_ACTION_SWAP] = NULL,
   [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
   [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
+  [SWFDEC_AS_ACTION_INCREMENT] = NULL,
+  [SWFDEC_AS_ACTION_DECREMENT] = NULL,
   [SWFDEC_AS_ACTION_CALL_METHOD] = vivi_decompile_call_method,
+  [SWFDEC_AS_ACTION_NEW_METHOD] = NULL,
+  [SWFDEC_AS_ACTION_INSTANCE_OF] = NULL,
+  [SWFDEC_AS_ACTION_ENUMERATE2] = NULL,
+  [SWFDEC_AS_ACTION_BREAKPOINT] = NULL,
   [SWFDEC_AS_ACTION_BIT_AND] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_BIT_OR] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_BIT_XOR] = vivi_decompile_binary,
@@ -614,15 +663,27 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_STRICT_EQUALS] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_GREATER] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_STRING_GREATER] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_EXTENDS] = NULL,
 
-  [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
+  [SWFDEC_AS_ACTION_GOTO_FRAME] = NULL,
+  [SWFDEC_AS_ACTION_GET_URL] = NULL,
   [SWFDEC_AS_ACTION_STORE_REGISTER] = vivi_decompile_store_register,
   [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
+  [SWFDEC_AS_ACTION_STRICT_MODE] = NULL,
+  [SWFDEC_AS_ACTION_WAIT_FOR_FRAME] = NULL,
+  [SWFDEC_AS_ACTION_SET_TARGET] = NULL,
+  [SWFDEC_AS_ACTION_GOTO_LABEL] = NULL,
+  [SWFDEC_AS_ACTION_WAIT_FOR_FRAME2] = NULL,
+  [SWFDEC_AS_ACTION_DEFINE_FUNCTION2] = NULL, /* handled directly */
+  [SWFDEC_AS_ACTION_TRY] = NULL,
+  [SWFDEC_AS_ACTION_WITH] = NULL,
+  [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
   [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
   [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
-  [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
-  [SWFDEC_AS_ACTION_DEFINE_FUNCTION2] = NULL, /* handled directly */
   [SWFDEC_AS_ACTION_DEFINE_FUNCTION] = NULL, /* handled directly */
+  [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
+  [SWFDEC_AS_ACTION_CALL] = NULL,
+  [SWFDEC_AS_ACTION_GOTO_FRAME2] = NULL
 };
 
 static gboolean
commit 5d6818f61c2af3f42923c52d80a5c547e091fc91
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 12:15:46 2008 +0100

    function definitions aren't const

diff --git a/vivified/code/vivi_code_function.c b/vivified/code/vivi_code_function.c
index f037056..94d282e 100644
--- a/vivified/code/vivi_code_function.c
+++ b/vivified/code/vivi_code_function.c
@@ -67,7 +67,7 @@ vivi_code_function_print (ViviCodeToken *token, ViviCodePrinter*printer)
 static gboolean
 vivi_code_function_is_constant (ViviCodeValue *value)
 {
-  return TRUE;
+  return FALSE;
 }
 
 static void
commit b965147e05638da0d50b9232cb1e0e1caca577d2
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 12:10:34 2008 +0100

    allow return to return a value

diff --git a/vivified/code/vivi_code_return.c b/vivified/code/vivi_code_return.c
index 0c1ca00..53fcfcc 100644
--- a/vivified/code/vivi_code_return.c
+++ b/vivified/code/vivi_code_return.c
@@ -27,17 +27,40 @@
 G_DEFINE_TYPE (ViviCodeReturn, vivi_code_return, VIVI_TYPE_CODE_STATEMENT)
 
 static void
+vivi_code_return_dispose (GObject *object)
+{
+  ViviCodeReturn *ret = VIVI_CODE_RETURN (object);
+
+  if (ret->value) {
+    g_object_unref (ret->value);
+    ret->value = NULL;
+  }
+
+  G_OBJECT_CLASS (vivi_code_return_parent_class)->dispose (object);
+}
+
+static void
 vivi_code_return_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
-  vivi_code_printer_print (printer, "return;");
+  ViviCodeReturn *ret = VIVI_CODE_RETURN (token);
+
+  vivi_code_printer_print (printer, "return");
+  if (ret->value) {
+    vivi_code_printer_print (printer, " ");
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (ret->value));
+  }
+  vivi_code_printer_print (printer, ";");
   vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
 vivi_code_return_class_init (ViviCodeReturnClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
 
+  object_class->dispose = vivi_code_return_dispose;
+
   token_class->print = vivi_code_return_print;
 }
 
@@ -52,3 +75,16 @@ vivi_code_return_new (void)
   return g_object_new (VIVI_TYPE_CODE_RETURN, NULL);
 }
 
+void
+vivi_code_return_set_value (ViviCodeReturn *ret, ViviCodeValue *value)
+{
+  g_return_if_fail (VIVI_IS_CODE_RETURN (ret));
+  g_return_if_fail (value == NULL || VIVI_IS_CODE_VALUE (value));
+
+  if (value)
+    g_object_ref (value);
+  if (ret->value)
+    g_object_unref (ret->value);
+  ret->value = value;
+}
+
diff --git a/vivified/code/vivi_code_return.h b/vivified/code/vivi_code_return.h
index dda801e..3e9faf6 100644
--- a/vivified/code/vivi_code_return.h
+++ b/vivified/code/vivi_code_return.h
@@ -21,6 +21,7 @@
 #define _VIVI_CODE_RETURN_H_
 
 #include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
 
 G_BEGIN_DECLS
 
@@ -38,6 +39,8 @@ typedef struct _ViviCodeReturnClass ViviCodeReturnClass;
 struct _ViviCodeReturn
 {
   ViviCodeStatement	statement;
+
+  ViviCodeValue *	value;
 };
 
 struct _ViviCodeReturnClass
@@ -49,6 +52,9 @@ GType			vivi_code_return_get_type   	(void);
 
 ViviCodeToken *		vivi_code_return_new		(void);
 
+void			vivi_code_return_set_value	(ViviCodeReturn *	ret,
+							 ViviCodeValue *	value);
+
 
 G_END_DECLS
 #endif
commit cbff92f883d26acf75a944a62fa6d02af83accce
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:50:47 2008 +0100

    preload registers start at index 1, not 0

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 86a4d64..4c63753 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -1368,7 +1368,7 @@ vivi_decompiler_preload (ViviDecompilerState *state, SwfdecScript *script)
       g_object_unref (value);
     }
   }
-  reg = 0;
+  reg = 1;
   for (i = 0; i < G_N_ELEMENTS (preloads); i++) {
     if (script->flags & preloads[i].flag) {
       ViviCodeValue *value = vivi_code_get_new_name (preloads[i].name);
commit 478702369585e00a5b856ba499fdf91d1c032a36
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:47:55 2008 +0100

    but we want the newline here

diff --git a/vivified/code/decompiler.c b/vivified/code/decompiler.c
index 5816037..8de2ffe 100644
--- a/vivified/code/decompiler.c
+++ b/vivified/code/decompiler.c
@@ -43,7 +43,7 @@ decode_script (gpointer offset, gpointer scriptp, gpointer unused)
   printer = vivi_code_text_printer_new ();
 
   vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (fun));
-  g_print ("\n");
+  g_print ("\n\n");
 
   g_object_unref (printer);
   g_object_unref (fun);
commit 4e9ee978dc4df0dd14295397450b494e1e2c50f2
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:47:11 2008 +0100

    no newline at end of function definition
    
    A function definition is not a statement.

diff --git a/vivified/code/vivi_code_function.c b/vivified/code/vivi_code_function.c
index b86636b..f037056 100644
--- a/vivified/code/vivi_code_function.c
+++ b/vivified/code/vivi_code_function.c
@@ -62,7 +62,6 @@ vivi_code_function_print (ViviCodeToken *token, ViviCodePrinter*printer)
     vivi_code_printer_pop_indentation (printer);
   }
   vivi_code_printer_print (printer, "}");
-  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static gboolean
commit 8595b91a3443588d428df867dbf8165fdf45c64e
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:43:22 2008 +0100

    implement StoreRegister

diff --git a/vivified/code/vivi_code_assignment.c b/vivified/code/vivi_code_assignment.c
index 1b9b444..45a4682 100644
--- a/vivified/code/vivi_code_assignment.c
+++ b/vivified/code/vivi_code_assignment.c
@@ -115,3 +115,17 @@ vivi_code_assignment_new (ViviCodeValue *from, ViviCodeValue *name, ViviCodeValu
   return VIVI_CODE_STATEMENT (assignment);
 }
 
+ViviCodeStatement *
+vivi_code_assignment_new_name (const char *name, ViviCodeValue *value)
+{
+  ViviCodeValue *constant;
+  ViviCodeStatement *result;
+
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  constant = vivi_code_constant_new_string (name);
+  result = vivi_code_assignment_new (NULL, constant, value);
+  g_object_unref (constant);
+  return result;
+}
diff --git a/vivified/code/vivi_code_assignment.h b/vivified/code/vivi_code_assignment.h
index ce621a7..56b3492 100644
--- a/vivified/code/vivi_code_assignment.h
+++ b/vivified/code/vivi_code_assignment.h
@@ -55,6 +55,8 @@ GType			vivi_code_assignment_get_type   	(void);
 ViviCodeStatement *	vivi_code_assignment_new		(ViviCodeValue *	from,
 								 ViviCodeValue *	name,
 								 ViviCodeValue *	value);
+ViviCodeStatement *	vivi_code_assignment_new_name		(const char *		name,
+								 ViviCodeValue *	value);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 66d803f..86a4d64 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -550,6 +550,36 @@ vivi_decompile_define_function (ViviDecompilerBlock *block, ViviDecompilerState
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_store_register (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *value;
+  
+  if (len != 1) {
+    vivi_decompiler_block_add_error (block, state, "invalid length %u in StoreRegister", len);
+    return FALSE;
+  }
+
+  value = vivi_decompiler_state_pop (state);
+  if (!vivi_code_value_is_constant (value)) {
+    ViviCodeStatement *assign;
+    char *name;
+
+    name = g_strdup_printf ("$reg%u", data[0]);
+    assign = vivi_code_assignment_new_name (name, value);
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), assign);
+    g_object_unref (assign);
+
+    g_object_unref (value);
+    value = vivi_code_get_new_name (name);
+    g_free (name);
+  }
+  vivi_decompiler_state_set_register (state, data[0], value);
+  vivi_decompiler_state_push (state, value);
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
@@ -586,6 +616,7 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_STRING_GREATER] = vivi_decompile_binary,
 
   [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
+  [SWFDEC_AS_ACTION_STORE_REGISTER] = vivi_decompile_store_register,
   [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
   [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
   [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
commit bbc0eff69628eb2cae813c9b2cdd855bbf2b57fc
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:43:14 2008 +0100

    function definitions are constant

diff --git a/vivified/code/vivi_code_function.c b/vivified/code/vivi_code_function.c
index 89a02f1..b86636b 100644
--- a/vivified/code/vivi_code_function.c
+++ b/vivified/code/vivi_code_function.c
@@ -65,15 +65,24 @@ vivi_code_function_print (ViviCodeToken *token, ViviCodePrinter*printer)
   vivi_code_printer_new_line (printer, FALSE);
 }
 
+static gboolean
+vivi_code_function_is_constant (ViviCodeValue *value)
+{
+  return TRUE;
+}
+
 static void
 vivi_code_function_class_init (ViviCodeFunctionClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
 
   object_class->dispose = vivi_code_function_dispose;
 
   token_class->print = vivi_code_function_print;
+
+  value_class->is_constant = vivi_code_function_is_constant;
 }
 
 static void
commit 2be0257b801bba699516cbc82a40aba17397bf83
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:14:21 2008 +0100

    add forgotten files

diff --git a/vivified/code/vivi_code_function.c b/vivified/code/vivi_code_function.c
new file mode 100644
index 0000000..89a02f1
--- /dev/null
+++ b/vivified/code/vivi_code_function.c
@@ -0,0 +1,100 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_code_function.h"
+#include "vivi_code_printer.h"
+
+#include "vivi_decompiler.h"
+
+G_DEFINE_TYPE (ViviCodeFunction, vivi_code_function, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_function_dispose (GObject *object)
+{
+  ViviCodeFunction *function = VIVI_CODE_FUNCTION (object);
+
+  swfdec_script_unref (function->script);
+  if (function->body)
+    g_object_unref (function->body);
+
+  G_OBJECT_CLASS (vivi_code_function_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_function_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviCodeFunction *function = VIVI_CODE_FUNCTION (token);
+  guint i;
+
+  vivi_code_printer_print (printer, "function (");
+  for (i = 0; i < function->script->n_arguments; i++) {
+    if (i != 0)
+      vivi_code_printer_print (printer, ", ");
+    vivi_code_printer_print (printer, function->script->arguments[i].name);
+  }
+  vivi_code_printer_print (printer, ") {");
+  vivi_code_printer_new_line (printer, FALSE);
+  if (function->body) {
+    vivi_code_printer_push_indentation (printer);
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (function->body));
+    vivi_code_printer_pop_indentation (printer);
+  }
+  vivi_code_printer_print (printer, "}");
+  vivi_code_printer_new_line (printer, FALSE);
+}
+
+static void
+vivi_code_function_class_init (ViviCodeFunctionClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_function_dispose;
+
+  token_class->print = vivi_code_function_print;
+}
+
+static void
+vivi_code_function_init (ViviCodeFunction *function)
+{
+  ViviCodeValue *value = VIVI_CODE_VALUE (function);
+
+  vivi_code_value_set_precedence (value, VIVI_PRECEDENCE_CALL);
+}
+
+ViviCodeValue *
+vivi_code_function_new (SwfdecScript *script)
+{
+  ViviCodeFunction *function;
+
+  g_return_val_if_fail (script != NULL, NULL);
+
+  function = g_object_new (VIVI_TYPE_CODE_FUNCTION, NULL);
+  function->script = swfdec_script_ref (script);
+  function->body = vivi_decompile_script (script);
+
+  return VIVI_CODE_VALUE (function);
+}
+
diff --git a/vivified/code/vivi_code_function.h b/vivified/code/vivi_code_function.h
new file mode 100644
index 0000000..1b33857
--- /dev/null
+++ b/vivified/code/vivi_code_function.h
@@ -0,0 +1,58 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_FUNCTION_H_
+#define _VIVI_CODE_FUNCTION_H_
+
+#include <vivified/code/vivi_code_value.h>
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeFunction ViviCodeFunction;
+typedef struct _ViviCodeFunctionClass ViviCodeFunctionClass;
+
+#define VIVI_TYPE_CODE_FUNCTION                    (vivi_code_function_get_type())
+#define VIVI_IS_CODE_FUNCTION(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_FUNCTION))
+#define VIVI_IS_CODE_FUNCTION_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_FUNCTION))
+#define VIVI_CODE_FUNCTION(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_FUNCTION, ViviCodeFunction))
+#define VIVI_CODE_FUNCTION_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_FUNCTION, ViviCodeFunctionClass))
+#define VIVI_CODE_FUNCTION_FUNCTION_CLASS(obj)          (G_TYPE_INSTANCE_FUNCTION_CLASS ((obj), VIVI_TYPE_CODE_FUNCTION, ViviCodeFunctionClass))
+
+struct _ViviCodeFunction
+{
+  ViviCodeValue		value;
+
+  SwfdecScript *	script;
+  ViviCodeStatement *	body;
+};
+
+struct _ViviCodeFunctionClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_function_get_type   	(void);
+
+ViviCodeValue *		vivi_code_function_new		(SwfdecScript *	script);
+
+
+G_END_DECLS
+#endif
commit 3c6fa7718694e731f758b6cbcdefc5d5143e34ac
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 11:14:09 2008 +0100

    preload variables according to script flags

diff --git a/vivified/code/vivi_code_get.c b/vivified/code/vivi_code_get.c
index 7aab6f5..edac7f9 100644
--- a/vivified/code/vivi_code_get.c
+++ b/vivified/code/vivi_code_get.c
@@ -116,3 +116,15 @@ vivi_code_get_new (ViviCodeValue *from, ViviCodeValue *name)
   return VIVI_CODE_VALUE (get);
 }
 
+ViviCodeValue *
+vivi_code_get_new_name (const char *name)
+{
+  ViviCodeValue *result, *constant;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  constant = vivi_code_constant_new_string (name);
+  result = vivi_code_get_new (NULL, constant);
+  g_object_unref (constant);
+  return result;
+}
diff --git a/vivified/code/vivi_code_get.h b/vivified/code/vivi_code_get.h
index e6c6d6c..fbdf13f 100644
--- a/vivified/code/vivi_code_get.h
+++ b/vivified/code/vivi_code_get.h
@@ -52,6 +52,7 @@ GType			vivi_code_get_get_type   	(void);
 
 ViviCodeValue *		vivi_code_get_new		(ViviCodeValue *	from,
 							 ViviCodeValue *	name);
+ViviCodeValue *		vivi_code_get_new_name		(const char *		name);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 467d95f..66d803f 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -1314,6 +1314,39 @@ vivi_decompiler_dump_graphviz (GList *blocks)
   g_string_free (string, TRUE);
 }
 
+static void
+vivi_decompiler_preload (ViviDecompilerState *state, SwfdecScript *script)
+{
+  static const struct {
+    const char *name;
+    guint	flag;
+  } preloads[] = {
+    { "this", SWFDEC_SCRIPT_PRELOAD_THIS },
+    { "arguments", SWFDEC_SCRIPT_PRELOAD_ARGS },
+    { "super", SWFDEC_SCRIPT_PRELOAD_SUPER },
+    { "_root", SWFDEC_SCRIPT_PRELOAD_ROOT },
+    { "_parent", SWFDEC_SCRIPT_PRELOAD_PARENT },
+    { "_global", SWFDEC_SCRIPT_PRELOAD_GLOBAL }
+  };
+  guint reg, i;
+
+  for (i = 0; i < script->n_arguments; i++) {
+    if (script->arguments[i].preload) {
+      ViviCodeValue *value = vivi_code_get_new_name (script->arguments[i].name);
+      vivi_decompiler_state_set_register (state, script->arguments[i].preload, value);
+      g_object_unref (value);
+    }
+  }
+  reg = 0;
+  for (i = 0; i < G_N_ELEMENTS (preloads); i++) {
+    if (script->flags & preloads[i].flag) {
+      ViviCodeValue *value = vivi_code_get_new_name (preloads[i].name);
+      vivi_decompiler_state_set_register (state, reg++, value);
+      g_object_unref (value);
+    }
+  }
+}
+
 ViviCodeStatement *
 vivi_decompile_script (SwfdecScript *script)
 {
@@ -1326,6 +1359,7 @@ vivi_decompile_script (SwfdecScript *script)
 
   DEBUG ("--> starting decompilation\n");
   state = vivi_decompiler_state_new (script, script->main, 4);
+  vivi_decompiler_preload (state, script);
   if (script->constant_pool) {
     vivi_decompiler_state_set_constant_pool (state,
 	swfdec_constant_pool_new (NULL, script->constant_pool, script->version));
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index 3b78965..0cdd743 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -130,6 +130,21 @@ vivi_decompiler_state_get_register (const ViviDecompilerState *state, guint reg)
     return g_object_ref (state->registers[reg]);
 }
 
+void
+vivi_decompiler_state_set_register (ViviDecompilerState *state, guint reg,
+    ViviCodeValue *value)
+{
+  g_return_if_fail (state != NULL);
+  g_return_if_fail (VIVI_IS_CODE_VALUE (value));
+
+  if (reg >= state->n_registers)
+    return;
+
+  if (state->registers[reg] != NULL)
+    g_object_unref (state->registers[reg]);
+  state->registers[reg] = g_object_ref (value);
+}
+
 const guint8 *
 vivi_decompiler_state_get_pc (const ViviDecompilerState *state)
 {
diff --git a/vivified/code/vivi_decompiler_state.h b/vivified/code/vivi_decompiler_state.h
index cad0031..54022fd 100644
--- a/vivified/code/vivi_decompiler_state.h
+++ b/vivified/code/vivi_decompiler_state.h
@@ -45,6 +45,9 @@ guint				vivi_decompiler_state_get_stack_depth
 								(const ViviDecompilerState *  	state);
 ViviCodeValue *			vivi_decompiler_state_get_register (const ViviDecompilerState *	state,
 								 guint				reg);
+void				vivi_decompiler_state_set_register (ViviDecompilerState *	state,
+								 guint				reg,
+								 ViviCodeValue *		value);
 
 const guint8 *			vivi_decompiler_state_get_pc	(const ViviDecompilerState *	state);
 void				vivi_decompiler_state_add_pc	(ViviDecompilerState *		state,
commit be79badcb42b54048abf18e990c3c50ab5583a34
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 10:37:53 2008 +0100

    handle constant pools in function calls
    
    also: constant pools are refcounted and refcounted objects are never const.

diff --git a/swfdec/swfdec_constant_pool.c b/swfdec/swfdec_constant_pool.c
index 3427a38..487af45 100644
--- a/swfdec/swfdec_constant_pool.c
+++ b/swfdec/swfdec_constant_pool.c
@@ -154,7 +154,7 @@ swfdec_constant_pool_unref (SwfdecConstantPool *pool)
  * Returns: The number of strings in this @pool
  **/
 guint
-swfdec_constant_pool_size (const SwfdecConstantPool *pool)
+swfdec_constant_pool_size (SwfdecConstantPool *pool)
 {
   g_return_val_if_fail (SWFDEC_IS_CONSTANT_POOL (pool), 0);
 
@@ -173,7 +173,7 @@ swfdec_constant_pool_size (const SwfdecConstantPool *pool)
  * Returns: the string at position @i
  **/
 const char *
-swfdec_constant_pool_get (const SwfdecConstantPool *pool, guint i)
+swfdec_constant_pool_get (SwfdecConstantPool *pool, guint i)
 {
   g_return_val_if_fail (SWFDEC_IS_CONSTANT_POOL (pool), NULL);
   g_return_val_if_fail (i < pool->n_strings, NULL);
diff --git a/swfdec/swfdec_constant_pool.h b/swfdec/swfdec_constant_pool.h
index 8ebc4dc..3592dbc 100644
--- a/swfdec/swfdec_constant_pool.h
+++ b/swfdec/swfdec_constant_pool.h
@@ -30,16 +30,16 @@ G_BEGIN_DECLS
 typedef struct _SwfdecConstantPool SwfdecConstantPool;
 
 
-SwfdecConstantPool *	swfdec_constant_pool_new	(SwfdecAsContext *		context,
-							 SwfdecBuffer *			buffer,
-							 guint				version);
-SwfdecConstantPool *	swfdec_constant_pool_ref      	(SwfdecConstantPool *		pool);
-void			swfdec_constant_pool_unref     	(SwfdecConstantPool *		pool);
-
-guint			swfdec_constant_pool_size	(const SwfdecConstantPool *	pool);
-const char *	  	swfdec_constant_pool_get	(const SwfdecConstantPool *	pool,
-							 guint				i);
-SwfdecBuffer *		swfdec_constant_pool_get_buffer	(SwfdecConstantPool *		pool);
+SwfdecConstantPool *	swfdec_constant_pool_new	(SwfdecAsContext *	context,
+							 SwfdecBuffer *		buffer,
+							 guint			version);
+SwfdecConstantPool *	swfdec_constant_pool_ref      	(SwfdecConstantPool *	pool);
+void			swfdec_constant_pool_unref     	(SwfdecConstantPool *	pool);
+
+guint			swfdec_constant_pool_size	(SwfdecConstantPool *	pool);
+const char *	  	swfdec_constant_pool_get	(SwfdecConstantPool *	pool,
+							 guint			i);
+SwfdecBuffer *		swfdec_constant_pool_get_buffer	(SwfdecConstantPool *	pool);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 9daf349..467d95f 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -170,7 +170,7 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
       case 9: /* 16bit ConstantPool address */
 	{
 	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
-	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
+	  SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
 	  if (pool == NULL) {
 	    vivi_decompiler_block_add_error (block, state, "no constant pool to push from");
 	    return TRUE;
@@ -528,10 +528,10 @@ vivi_decompile_define_function (ViviDecompilerBlock *block, ViviDecompilerState
     g_free (function_name);
     return FALSE;
   }
-#if 0
-  if (frame->constant_pool_buffer)
-    script->constant_pool = swfdec_buffer_ref (frame->constant_pool_buffer);
-#endif
+  if (vivi_decompiler_state_get_constant_pool (state)) {
+    script->constant_pool = swfdec_buffer_ref (swfdec_constant_pool_get_buffer (
+	  vivi_decompiler_state_get_constant_pool (state)));
+  }
   script->flags = flags;
   script->n_registers = n_registers;
   script->n_arguments = n_args;
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index f022b07..3b78965 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -148,7 +148,7 @@ vivi_decompiler_state_get_script (const ViviDecompilerState *state)
   return state->script;
 }
 
-const SwfdecConstantPool *
+SwfdecConstantPool *
 vivi_decompiler_state_get_constant_pool (const ViviDecompilerState *state)
 {
   return state->pool;
diff --git a/vivified/code/vivi_decompiler_state.h b/vivified/code/vivi_decompiler_state.h
index 041b624..cad0031 100644
--- a/vivified/code/vivi_decompiler_state.h
+++ b/vivified/code/vivi_decompiler_state.h
@@ -50,7 +50,7 @@ const guint8 *			vivi_decompiler_state_get_pc	(const ViviDecompilerState *	state
 void				vivi_decompiler_state_add_pc	(ViviDecompilerState *		state,
 								 int				diff);
 SwfdecScript *	        	vivi_decompiler_state_get_script(const ViviDecompilerState *	state);
-const SwfdecConstantPool *    	vivi_decompiler_state_get_constant_pool 
+SwfdecConstantPool *    	vivi_decompiler_state_get_constant_pool 
 								(const ViviDecompilerState *	state);
 void				vivi_decompiler_state_set_constant_pool 
 								(ViviDecompilerState *		state, 
commit 50a8b1010390ea9222672c8090f704722bf0c5e7
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 10:32:48 2008 +0100

    disable debugging prints

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index e8c0571..9daf349 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -50,13 +50,13 @@
 #include "vivi_decompiler_state.h"
 #include "vivi_decompiler_unknown.h"
 
-#if 1
+#if 0
 #define DEBUG g_printerr
 #else
 #define DEBUG(...)
 #endif
 
-#if 1
+#if 0
 static G_GNUC_UNUSED void
 DUMP_BLOCKS (GList *blocks)
 {
commit adcf30aada78d2dd2982f126dd261ad9f00020c3
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 10:32:30 2008 +0100

    print empty line between decompiled functions

diff --git a/vivified/code/decompiler.c b/vivified/code/decompiler.c
index 146f4f4..5816037 100644
--- a/vivified/code/decompiler.c
+++ b/vivified/code/decompiler.c
@@ -43,6 +43,7 @@ decode_script (gpointer offset, gpointer scriptp, gpointer unused)
   printer = vivi_code_text_printer_new ();
 
   vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (fun));
+  g_print ("\n");
 
   g_object_unref (printer);
   g_object_unref (fun);
commit 28be9c717f8950253c28f0ee9c1faccf9b2703cc
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 10:32:15 2008 +0100

    update to new way of writing tests

diff --git a/vivified/code/test/and-or.swf.expect b/vivified/code/test/and-or.swf.expect
index 62706cd..93440ba 100644
--- a/vivified/code/test/and-or.swf.expect
+++ b/vivified/code/test/and-or.swf.expect
@@ -1,7 +1,7 @@
 /* version: 7 - size: 200x150 */
 
 /* Sprite0_Frame0 */
-{
+function () {
   if (1 && 2)
     trace (3);
   if (1 || 2)
diff --git a/vivified/code/test/hello-world.swf.expect b/vivified/code/test/hello-world.swf.expect
index bdda181..aa94505 100644
--- a/vivified/code/test/hello-world.swf.expect
+++ b/vivified/code/test/hello-world.swf.expect
@@ -1,7 +1,7 @@
 /* version: 7 - size: 200x150 */
 
 /* Sprite0_Frame0 */
-{
+function () {
   trace ("Hello World!");
   loadMovie ("fscommand:quit", "");
 }
diff --git a/vivified/code/test/if-nested.swf.expect b/vivified/code/test/if-nested.swf.expect
index 828337a..a4b332a 100644
--- a/vivified/code/test/if-nested.swf.expect
+++ b/vivified/code/test/if-nested.swf.expect
@@ -1,7 +1,7 @@
 /* version: 7 - size: 200x150 */
 
 /* Sprite0_Frame0 */
-{
+function () {
   if (1) {
     if (2)
       trace ("one");
diff --git a/vivified/code/test/if.swf.expect b/vivified/code/test/if.swf.expect
index 80a3fd1..ae8a43b 100644
--- a/vivified/code/test/if.swf.expect
+++ b/vivified/code/test/if.swf.expect
@@ -1,7 +1,7 @@
 /* version: 7 - size: 200x150 */
 
 /* Sprite0_Frame0 */
-{
+function () {
   if (1)
     trace ("Hello World!");
   else
diff --git a/vivified/code/test/loop-nested.swf.expect b/vivified/code/test/loop-nested.swf.expect
index f23ec3d..eabc878 100644
--- a/vivified/code/test/loop-nested.swf.expect
+++ b/vivified/code/test/loop-nested.swf.expect
@@ -1,7 +1,7 @@
 /* version: 7 - size: 200x150 */
 
 /* Sprite0_Frame0 */
-{
+function () {
   while (5 < i)
     while (j < 10 * -1)
       trace ("Hello");
diff --git a/vivified/code/test/simple-loop.swf.expect b/vivified/code/test/simple-loop.swf.expect
index 225bac3..f0a1bbf 100644
--- a/vivified/code/test/simple-loop.swf.expect
+++ b/vivified/code/test/simple-loop.swf.expect
@@ -1,7 +1,7 @@
 /* version: 7 - size: 200x150 */
 
 /* Sprite0_Frame0 */
-{
+function () {
   while (false)
     trace ("Hello World!");
 }
commit 414b6bd927d151577e1d8906bbab7fdb7ff2fe48
Merge: 9f34b0e... e666189...
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 26 10:25:45 2008 +0100

    Merge branch 'master' into decompiler
    
    Conflicts:
    
    	swfdec/swfdec_script.c
    	swfdec/swfdec_script_internal.h

diff --cc swfdec/swfdec_constant_pool.c
index 0000000,487af45..3427a38
mode 000000,100644..100644
--- a/swfdec/swfdec_constant_pool.c
+++ b/swfdec/swfdec_constant_pool.c
@@@ -1,0 -1,199 +1,199 @@@
+ /* Swfdec
+  * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2.1 of the License, or (at your option) any later version.
+  * 
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  * 
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+  * Boston, MA  02110-1301  USA
+  */
+ 
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+ 
+ #include "swfdec_constant_pool.h"
+ #include "swfdec_bits.h"
+ #include "swfdec_debug.h"
+ 
+ struct _SwfdecConstantPool {
+   SwfdecAsContext *	context;	/* context we are attached to or NULL */
+   SwfdecBuffer *	buffer;		/* the buffer the strings were read from */
+   guint			refcount;	/* reference count */
+   guint			n_strings;	/* number of strings */
+   char *		strings[1];	/* n_strings strings */
+ };
+ 
+ /**
+  * swfdec_constant_pool_new:
+  * @context: a context to attach strings to or %NULL
+  * @buffer: buffer to read constant pool from
+  * @version: the Flash version to use when reading the strings
+  *
+  * Creates a new constant pool from the given @buffer. If the buffer is in the 
+  * wrong format, %NULL is returned. If a @context was given, the strings are 
+  * added to the context. This means the strings in the pool will be 
+  * garbage-collected already. When using a non-%NULL @context, the pool does 
+  * will not add a reference to the context. It is your responsibility to hold a
+  * reference to the context while you use the pool.
+  *
+  * Returns: a new constant pool or %NULL
+  **/
+ SwfdecConstantPool *
+ swfdec_constant_pool_new (SwfdecAsContext *context, SwfdecBuffer *buffer, guint version)
+ {
+   guint i, n;
+   gsize size;
+   SwfdecBits bits;
+   SwfdecConstantPool *pool;
+ 
+   g_return_val_if_fail (context == NULL || SWFDEC_IS_AS_CONTEXT (context), NULL);
+   g_return_val_if_fail (buffer != NULL, NULL);
+ 
+   /* try to find the pool in the context's cache */
+   if (context) {
+     pool = g_hash_table_lookup (context->constant_pools, buffer->data);
+     if (pool)
+       return swfdec_constant_pool_ref (pool);
+   }
+ 
+   swfdec_bits_init (&bits, buffer);
+ 
+   n = swfdec_bits_get_u16 (&bits);
+   if (n == 0)
+     return NULL;
+ 
+   size = sizeof (SwfdecConstantPool) + (n - 1) * sizeof (char *);
+   pool = g_slice_alloc0 (size);
+   pool->n_strings = n;
+   for (i = 0; i < n; i++) {
+     pool->strings[i] = swfdec_bits_get_string (&bits, version);
+     if (pool->strings[i] == NULL) {
+       SWFDEC_ERROR ("not enough strings available");
+       g_slice_free1 (size, pool);
+       return NULL;
+     }
+     if (context)
+       pool->strings[i] = (char *) swfdec_as_context_give_string (context, pool->strings[i]);
+   }
+   if (swfdec_bits_left (&bits)) {
+     SWFDEC_WARNING ("constant pool didn't consume whole buffer (%u bytes leftover)", swfdec_bits_left (&bits) / 8);
+   }
+   pool->buffer = swfdec_buffer_ref (buffer);
+   pool->refcount = 1;
+   /* put pool into the context's cache */
+   if (context) {
+     pool->context = context;
+     g_hash_table_insert (context->constant_pools, buffer->data, pool);
+   }
+   return pool;
+ }
+ 
+ /**
+  * swfdec_constant_pool_ref:
+  * @pool: a constant pool
+  *
+  * Increases the constant pool's reference by one.
+  *
+  * Returns: the passed in @pool.
+  **/
+ SwfdecConstantPool *
+ swfdec_constant_pool_ref (SwfdecConstantPool *pool)
+ {
+   g_return_val_if_fail (SWFDEC_IS_CONSTANT_POOL (pool), NULL);
+ 
+   pool->refcount++;
+ 
+   return pool;
+ }
+ 
+ /**
+  * swfdec_constant_pool_unref:
+  * @pool: the pool to unref
+  *
+  * Removes a reference from the pool. If no more references are left, the pool
+  * will be freed.
+  **/
+ void
+ swfdec_constant_pool_unref (SwfdecConstantPool *pool)
+ {
+   g_return_if_fail (SWFDEC_IS_CONSTANT_POOL (pool));
+   g_return_if_fail (pool->refcount > 0);
+ 
+   pool->refcount--;
+   if (pool->refcount)
+     return;
+ 
+   if (pool->context) {
+     g_hash_table_remove (pool->context->constant_pools, pool->buffer->data);
+   } else {
+     guint i;
+     for (i = 0; i < pool->n_strings; i++) {
+       g_free (pool->strings[i]);
+     }
+   }
+   swfdec_buffer_unref (pool->buffer);
+   g_slice_free1 (sizeof (SwfdecConstantPool) + (pool->n_strings - 1) * sizeof (char *), pool);
+ }
+ 
+ /**
+  * swfdec_constant_pool_size:
+  * @pool: a pool
+  *
+  * Queries the number of strings in this pool.
+  *
+  * Returns: The number of strings in this @pool
+  **/
+ guint
 -swfdec_constant_pool_size (SwfdecConstantPool *pool)
++swfdec_constant_pool_size (const SwfdecConstantPool *pool)
+ {
+   g_return_val_if_fail (SWFDEC_IS_CONSTANT_POOL (pool), 0);
+ 
+   return pool->n_strings;
+ }
+ 
+ /**
+  * swfdec_constant_pool_get:
+  * @pool: a pool
+  * @i: index of the string to get
+  *
+  * Gets the requested string from the pool. The index must not excess the 
+  * number of elements in the pool. If the constant pool was created with a 
+  * context attached, the returned string will be garbage-collected already.
+  *
+  * Returns: the string at position @i
+  **/
+ const char *
 -swfdec_constant_pool_get (SwfdecConstantPool *pool, guint i)
++swfdec_constant_pool_get (const SwfdecConstantPool *pool, guint i)
+ {
+   g_return_val_if_fail (SWFDEC_IS_CONSTANT_POOL (pool), NULL);
+   g_return_val_if_fail (i < pool->n_strings, NULL);
+ 
+   return pool->strings[i];
+ }
+ 
+ /**
+  * swfdec_constant_pool_get_buffer:
+  * @pool: a constant pool
+  *
+  * Gets the buffer the pool was created from
+  *
+  * Returns: the buffer this pool was created from.
+  **/
+ SwfdecBuffer *
+ swfdec_constant_pool_get_buffer (SwfdecConstantPool *pool)
+ {
+   g_return_val_if_fail (SWFDEC_IS_CONSTANT_POOL (pool), NULL);
+ 
+   return pool->buffer;
+ }
+ 
diff --cc swfdec/swfdec_constant_pool.h
index 0000000,3592dbc..8ebc4dc
mode 000000,100644..100644
--- a/swfdec/swfdec_constant_pool.h
+++ b/swfdec/swfdec_constant_pool.h
@@@ -1,0 -1,47 +1,47 @@@
+ /* Swfdec
+  * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2.1 of the License, or (at your option) any later version.
+  * 
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  * 
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+  * Boston, MA  02110-1301  USA
+  */
+ 
+ #ifndef _SWFDEC_CONSTANT_POOL_H_
+ #define _SWFDEC_CONSTANT_POOL_H_
+ 
+ #include <swfdec/swfdec.h>
+ 
+ G_BEGIN_DECLS
+ 
+ 
+ #define SWFDEC_IS_CONSTANT_POOL(pool) ((pool) != NULL)
+ 
+ typedef struct _SwfdecConstantPool SwfdecConstantPool;
+ 
+ 
 -SwfdecConstantPool *	swfdec_constant_pool_new	(SwfdecAsContext *	context,
 -							 SwfdecBuffer *		buffer,
 -							 guint			version);
 -SwfdecConstantPool *	swfdec_constant_pool_ref      	(SwfdecConstantPool *	pool);
 -void			swfdec_constant_pool_unref     	(SwfdecConstantPool *	pool);
 -
 -guint			swfdec_constant_pool_size	(SwfdecConstantPool *	pool);
 -const char *	  	swfdec_constant_pool_get	(SwfdecConstantPool *	pool,
 -							 guint			i);
 -SwfdecBuffer *		swfdec_constant_pool_get_buffer	(SwfdecConstantPool *	pool);
++SwfdecConstantPool *	swfdec_constant_pool_new	(SwfdecAsContext *		context,
++							 SwfdecBuffer *			buffer,
++							 guint				version);
++SwfdecConstantPool *	swfdec_constant_pool_ref      	(SwfdecConstantPool *		pool);
++void			swfdec_constant_pool_unref     	(SwfdecConstantPool *		pool);
++
++guint			swfdec_constant_pool_size	(const SwfdecConstantPool *	pool);
++const char *	  	swfdec_constant_pool_get	(const SwfdecConstantPool *	pool,
++							 guint				i);
++SwfdecBuffer *		swfdec_constant_pool_get_buffer	(SwfdecConstantPool *		pool);
+ 
+ 
+ G_END_DECLS
+ 
+ #endif
diff --cc swfdec/swfdec_script_internal.h
index 75f412c,3546b3d..086f159
--- a/swfdec/swfdec_script_internal.h
+++ b/swfdec/swfdec_script_internal.h
@@@ -68,29 -68,16 +68,16 @@@ struct _SwfdecScriptArgument 
  const char *	swfdec_action_get_name		(guint			action);
  guint		swfdec_action_get_from_name	(const char *		name);
  
- SwfdecConstantPool *
- 		swfdec_constant_pool_new_from_action	(const guint8 *			data,
- 							 guint				len,
- 							 guint				version);
- void		swfdec_constant_pool_free	  	(SwfdecConstantPool *		pool);
- SwfdecConstantPool *
- 		swfdec_constant_pool_copy		(const SwfdecConstantPool *	pool);
- guint		swfdec_constant_pool_size		(const SwfdecConstantPool *	pool);
- const char *	swfdec_constant_pool_get		(const SwfdecConstantPool *	pool,
- 							 guint				i);
- void		swfdec_constant_pool_attach_to_context	(SwfdecConstantPool *		pool,
- 							 SwfdecAsContext *		context);
- 
 -SwfdecScript *	swfdec_script_new_from_bits   		(SwfdecBits *		bits,
 -							 const char *		name,
 -							 guint			version);
 +SwfdecScript *	swfdec_script_new_from_bits   		(SwfdecBits *			bits,
 +							 const char *			name,
 +							 guint				version);
  
 -gboolean	swfdec_script_foreach			(SwfdecScript *		script,
 -							 SwfdecScriptForeachFunc func,
 -							 gpointer		user_data);
 -char *		swfdec_script_print_action		(guint			action,
 -							 const guint8 *		data,
 -							 guint			len);
 +gboolean	swfdec_script_foreach			(SwfdecScript *			script,
 +							 SwfdecScriptForeachFunc	func,
 +							 gpointer			user_data);
 +char *		swfdec_script_print_action		(guint				action,
 +							 const guint8 *			data,
 +							 guint				len);
  
  G_END_DECLS
  
diff --cc vivified/code/vivi_decompiler.c
index f3f3237,0000000..e8c0571
mode 100644,000000..100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@@ -1,1347 -1,0 +1,1352 @@@
 +/* Vivified
 + * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + * 
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 + * Boston, MA  02110-1301  USA
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#include <string.h>
 +
 +#include <swfdec/swfdec_as_interpret.h>
 +#include <swfdec/swfdec_bits.h>
 +#include <swfdec/swfdec_script_internal.h>
 +
 +#include "vivi_decompiler.h"
 +#include "vivi_code_assignment.h"
 +#include "vivi_code_binary.h"
 +#include "vivi_code_block.h"
 +#include "vivi_code_break.h"
 +#include "vivi_code_constant.h"
 +#include "vivi_code_continue.h"
 +#include "vivi_code_function.h"
 +#include "vivi_code_function_call.h"
 +#include "vivi_code_get.h"
 +#include "vivi_code_get_url.h"
 +#include "vivi_code_goto.h"
 +#include "vivi_code_if.h"
 +#include "vivi_code_loop.h"
 +#include "vivi_code_return.h"
 +#include "vivi_code_trace.h"
 +#include "vivi_code_unary.h"
 +#include "vivi_code_value_statement.h"
 +#include "vivi_decompiler_block.h"
 +#include "vivi_decompiler_duplicate.h"
 +#include "vivi_decompiler_state.h"
 +#include "vivi_decompiler_unknown.h"
 +
 +#if 1
 +#define DEBUG g_printerr
 +#else
 +#define DEBUG(...)
 +#endif
 +
 +#if 1
 +static G_GNUC_UNUSED void
 +DUMP_BLOCKS (GList *blocks)
 +{
 +  GList *walk;
 +
 +  g_print ("dumping blocks:\n");
 +  for (walk = blocks; walk; walk = walk->next) {
 +    ViviDecompilerBlock *block = walk->data;
 +    g_printerr ("  %p -> %p\n", vivi_decompiler_block_get_start (block), 
 +	block->end ? vivi_decompiler_state_get_pc (block->end) : NULL);
 +  }
 +}
 +#else
 +#define DUMP_BLOCKS(dec) (void) 0
 +#endif
 +
 +static ViviDecompilerBlock *
 +vivi_decompiler_push_block_for_state (GList **blocks, ViviDecompilerState *state)
 +{
 +  ViviDecompilerBlock *block;
 +  GList *walk;
 +  const guint8 *pc, *block_start;
 +
 +  pc = vivi_decompiler_state_get_pc (state);
 +  DEBUG ("pc: %p\n", pc);
 +  DUMP_BLOCKS (*blocks);
 +  for (walk = *blocks; walk; walk = walk->next) {
 +    block = walk->data;
 +    block_start = vivi_decompiler_block_get_start (block);
 +    if (block_start < pc) {
 +      if (vivi_decompiler_block_contains (block, pc)) {
 +	vivi_decompiler_block_reset (block, FALSE);
 +	walk = walk->next;
 +	break;
 +      }
 +      continue;
 +    }
 +    if (block_start == pc) {
 +      const ViviDecompilerState *block_state = vivi_decompiler_block_get_start_state (block);
 +
 +      if (!vivi_decompiler_state_is_compatible (block_state, state)) {
 +	g_printerr ("incompatible states, the decompiled code will be _really_ fucked up.\n");
 +	vivi_decompiler_state_free (state);
 +	return block;
 +      }
 +      if (!vivi_decompiler_block_is_compatible (block, state))
 +	vivi_decompiler_block_reset (block, TRUE);
 +      vivi_decompiler_state_free (state);
 +      return block;
 +    }
 +    break;
 +  }
 +
 +  /* FIXME: see if the block is already there! */
 +  block = vivi_decompiler_block_new (state);
 +  *blocks = g_list_insert_before (*blocks, walk, block);
 +  return block;
 +}
 +
 +/*** BYTECODE DECOMPILER ***/
 +
 +typedef gboolean (* DecompileFunc) (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +          guint code, const guint8 *data, guint len);
 +
 +static gboolean
 +vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *val;
 +  SwfdecBits bits;
 +  guint type;
 +
 +  swfdec_bits_init_data (&bits, data, len);
 +  while (swfdec_bits_left (&bits)) {
 +    type = swfdec_bits_get_u8 (&bits);
 +    switch (type) {
 +      case 0: /* string */
 +	{
 +	  char *s = swfdec_bits_get_string (&bits, vivi_decompiler_state_get_version (state));
 +	  if (s == NULL) {
 +	    vivi_decompiler_block_add_error (block, state, "could not read string");
 +	    return FALSE;
 +	  }
 +	  val = vivi_code_constant_new_string (s);
 +	  g_free (s);
 +	  break;
 +	}
 +      case 1: /* float */
 +	val = vivi_code_constant_new_number (swfdec_bits_get_float (&bits));
 +	break;
 +      case 2: /* null */
 +	val = vivi_code_constant_new_null ();
 +	break;
 +      case 3: /* undefined */
 +	val = vivi_code_constant_new_undefined ();
 +	break;
 +      case 4: /* register */
 +	val = vivi_decompiler_state_get_register (
 +	      state, swfdec_bits_get_u8 (&bits));
 +	break;
 +      case 5: /* boolean */
 +	val = vivi_code_constant_new_boolean (swfdec_bits_get_u8 (&bits) ? TRUE : FALSE);
 +	break;
 +      case 6: /* double */
 +	val = vivi_code_constant_new_number (swfdec_bits_get_double (&bits));
 +	break;
 +      case 7: /* 32bit int */
 +	val = vivi_code_constant_new_int ((int) swfdec_bits_get_u32 (&bits));
 +	break;
 +      case 8: /* 8bit ConstantPool address */
 +      case 9: /* 16bit ConstantPool address */
 +	{
 +	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
 +	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
 +	  if (pool == NULL) {
 +	    vivi_decompiler_block_add_error (block, state, "no constant pool to push from");
 +	    return TRUE;
 +	  }
 +	  if (i >= swfdec_constant_pool_size (pool)) {
 +	    vivi_decompiler_block_add_error (block, state, "constant pool index %u too high - only %u elements",
 +		i, swfdec_constant_pool_size (pool));
 +	    return TRUE;
 +	  }
 +	  val = vivi_code_constant_new_string (swfdec_constant_pool_get (pool, i));
 +	  break;
 +	}
 +      default:
 +	vivi_decompiler_block_add_error (block, state, "Push: type %u not implemented", type);
 +	return TRUE;
 +    }
 +    vivi_decompiler_state_push (state, val);
 +  }
 +
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_pop (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeStatement *stmt;
 +  ViviCodeValue *val;
 +  
 +  val = vivi_decompiler_state_pop (state);
 +  stmt = vivi_code_value_statement_new (val);
 +  g_object_unref (val);
 +  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
 +  g_object_unref (stmt);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_constant_pool (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
-   SwfdecConstantPool *pool = swfdec_constant_pool_new_from_action (data, len, 
++  SwfdecConstantPool *pool;
++  SwfdecBuffer *buffer;
++  
++  buffer = vivi_decompiler_state_get_script (state)->buffer;
++  buffer = swfdec_buffer_new_subbuffer (buffer, data - buffer->data, len);
++  pool = swfdec_constant_pool_new (NULL, buffer, 
 +      vivi_decompiler_state_get_version (state));
++  swfdec_buffer_unref (buffer);
 +
 +  vivi_decompiler_state_set_constant_pool (state, pool);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_trace (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeStatement *trace;
 +  ViviCodeValue *val;
 +  
 +  val = vivi_decompiler_state_pop (state);
 +  trace = vivi_code_trace_new (val);
 +  g_object_unref (val);
 +  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), trace);
 +  g_object_unref (trace);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_end (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  vivi_decompiler_block_finish (block, state);
 +  return FALSE;
 +}
 +
 +static gboolean
 +vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *url, *target;
 +
 +  target = vivi_decompiler_state_pop (state);
 +  url = vivi_decompiler_state_pop (state);
 +
 +  if (len != 1) {
 +    vivi_decompiler_block_add_error (block, state, "invalid length in getURL2 command");   
 +  } else {
 +    ViviCodeStatement *stmt;
 +    guint method = data[0] & 3;
 +    guint internal = data[0] & 64;
 +    guint variables = data[0] & 128;
 +
 +    stmt = vivi_code_get_url_new (target, url, method, internal, variables);
 +    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
 +    g_object_unref (stmt);
 +  }
 +  g_object_unref (target);
 +  g_object_unref (url);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *val, *unary;
 +
 +  val = vivi_decompiler_state_pop (state);
 +  unary = vivi_code_unary_new (val, '!');
 +  vivi_decompiler_state_push (state, unary);
 +  g_object_unref (val);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_get_variable (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *get, *name;
 +
 +  name = vivi_decompiler_state_pop (state);
 +  get = vivi_code_get_new (NULL, name);
 +  g_object_unref (name);
 +  vivi_decompiler_state_push (state, get);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_get_member (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *get, *from, *name;
 +
 +  name = vivi_decompiler_state_pop (state);
 +  from = vivi_decompiler_state_pop (state);
 +  get = vivi_code_get_new (from, name);
 +  g_object_unref (from);
 +  g_object_unref (name);
 +  vivi_decompiler_state_push (state, get);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_set_variable (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *name, *value;
 +  ViviCodeStatement *assign;
 +
 +  value = vivi_decompiler_state_pop (state);
 +  name = vivi_decompiler_state_pop (state);
 +  assign = vivi_code_assignment_new (NULL, name, value);
 +  g_object_unref (name);
 +  g_object_unref (value);
 +  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), assign);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_set_member (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *from, *name, *value;
 +  ViviCodeStatement *assign;
 +
 +  value = vivi_decompiler_state_pop (state);
 +  name = vivi_decompiler_state_pop (state);
 +  from = vivi_decompiler_state_pop (state);
 +  assign = vivi_code_assignment_new (from, name, value);
 +  g_object_unref (from);
 +  g_object_unref (name);
 +  g_object_unref (value);
 +  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), assign);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_binary (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *right, *left, *result;
 +
 +  right = vivi_decompiler_state_pop (state);
 +  left = vivi_decompiler_state_pop (state);
 +  result = vivi_code_binary_new_bytecode (left, right, code);
 +  g_object_unref (left);
 +  g_object_unref (right);
 +  vivi_decompiler_state_push (state, result);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_duplicate (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *value, *dupl;
 +
 +  value = vivi_decompiler_state_pop (state);
 +  vivi_decompiler_state_push (state, value);
 +  dupl = vivi_decompiler_duplicate_new (value);
 +  vivi_decompiler_state_push (state, dupl);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_function_call (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    ViviCodeValue *value, ViviCodeValue *name, ViviCodeValue *args)
 +{
 +  ViviCodeValue *call;
 +  double d;
 +  guint i, count;
 +
 +  call = vivi_code_function_call_new (value, name);
 +  if (value)
 +    g_object_unref (value);
 +  if (name)
 +    g_object_unref (name);
 +
 +  if (!VIVI_IS_CODE_CONSTANT (args) || 
 +      vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (args)) != SWFDEC_AS_TYPE_NUMBER ||
 +      ((count = d = vivi_code_constant_get_number (VIVI_CODE_CONSTANT (args))) != d)) {
 +    vivi_decompiler_block_add_error (block, state, "could not determine function argument count");
 +    g_object_unref (args);
 +    g_object_unref (call);
 +    return FALSE;
 +  }
 +  g_object_unref (args);
 +
 +  count = MIN (count, vivi_decompiler_state_get_stack_depth (state));
 +  for (i = 0; i < count; i++) {
 +    value = vivi_decompiler_state_pop (state);
 +    vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (call), value);
 +    g_object_unref (value);
 +  }
 +  vivi_decompiler_state_push (state, call);
 +  return TRUE;
 +}
 +
 +static gboolean
 +vivi_decompile_call_function (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *name, *args;
 +
 +  name = vivi_decompiler_state_pop (state);
 +  args = vivi_decompiler_state_pop (state);
 +
 +  return vivi_decompile_function_call (block, state, NULL, name, args);
 +}
 +
 +static gboolean
 +vivi_decompile_call_method (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *value, *name, *args;
 +
 +  name = vivi_decompiler_state_pop (state);
 +  value = vivi_decompiler_state_pop (state);
 +  args = vivi_decompiler_state_pop (state);
 +
 +  return vivi_decompile_function_call (block, state, value, name, args);
 +}
 +
 +static gboolean
 +vivi_decompile_define_function (ViviDecompilerBlock *block, ViviDecompilerState *state,
 +    guint code, const guint8 *data, guint len)
 +{
 +  ViviCodeValue *value;
 +  char *function_name;
 +  const char *name = NULL;
 +  guint i, n_args, size, n_registers;
 +  SwfdecBits bits;
 +  SwfdecBuffer *buffer;
 +  SwfdecScript *script;
 +  guint flags = 0;
 +  SwfdecScriptArgument *args;
 +  gboolean v2 = (code == 0x8e);
 +
 +  swfdec_bits_init_data (&bits, data, len);
 +  script = vivi_decompiler_state_get_script (state);
 +  function_name = swfdec_bits_get_string (&bits, script->version);
 +  if (function_name == NULL) {
 +    vivi_decompiler_block_add_error (block, state, "could not parse function name");
 +    return FALSE;
 +  }
 +  n_args = swfdec_bits_get_u16 (&bits);
 +  if (v2) {
 +    n_registers = swfdec_bits_get_u8 (&bits);
 +    if (n_registers == 0)
 +      n_registers = 4;
 +    flags = swfdec_bits_get_u16 (&bits);
 +  } else {
 +    n_registers = 5;
 +  }
 +  if (n_args) {
 +    args = g_new0 (SwfdecScriptArgument, n_args);
 +    for (i = 0; i < n_args && swfdec_bits_left (&bits); i++) {
 +      if (v2) {
 +	args[i].preload = swfdec_bits_get_u8 (&bits);
 +	if (args[i].preload && args[i].preload >= n_registers) {
 +	  vivi_decompiler_block_add_error (block, state, 
 +	      "argument %u cannot be preloaded into register %u out of %u", 
 +	      i, args[i].preload, n_registers);
 +	  /* FIXME: figure out correct error handling here */
 +	  args[i].preload = 0;
 +	}
 +      }
 +      args[i].name = swfdec_bits_get_string (&bits, script->version);
 +      if (args[i].name == NULL || args[i].name == '\0') {
 +	vivi_decompiler_block_add_error (block, state, "empty argument name not allowed");
 +	g_free (args);
 +	return FALSE;
 +      }
 +      /* FIXME: check duplicate arguments */
 +    }
 +  } else {
 +    args = NULL;
 +  }
 +  size = swfdec_bits_get_u16 (&bits);
 +  buffer = script->buffer;
 +  /* check the script can be created */
 +  if (vivi_decompiler_state_get_pc (state) + 3 + len + size > buffer->data + buffer->length) {
 +    vivi_decompiler_block_add_error (block, state, "size of function is too big");
 +    g_free (args);
 +    g_free (function_name);
 +    return FALSE;
 +  }
 +  /* create the script */
 +  buffer = swfdec_buffer_new_subbuffer (buffer, 
 +      vivi_decompiler_state_get_pc (state) + 3 + len - buffer->data, size);
 +  swfdec_bits_init (&bits, buffer);
 +  if (*function_name) {
 +    name = function_name;
 +  } else if (vivi_decompiler_state_get_stack_depth (state) > 0) {
 +    /* This is kind of a hack that uses a feature of the Adobe compiler:
 +     * foo = function () {} is compiled as these actions:
 +     * Push "foo", DefineFunction, SetVariable/SetMember
 +     * With this knowledge we can inspect the topmost stack member, since
 +     * it will contain the name this function will soon be assigned to.
 +     */
 +    value = vivi_decompiler_state_peek_nth (state, 0);
 +    if (VIVI_IS_CODE_CONSTANT (value) &&
 +	vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (value)) == SWFDEC_AS_TYPE_STRING)
 +      name = SWFDEC_AS_VALUE_GET_STRING (&VIVI_CODE_CONSTANT (value)->value);
 +  }
 +  if (name == NULL)
 +    name = "unnamed_function";
 +  script = swfdec_script_new_from_bits (&bits, name, script->version);
 +  swfdec_buffer_unref (buffer);
 +  if (script == NULL) {
 +    vivi_decompiler_block_add_error (block, state, "failed to create script");
 +    g_free (args);
 +    g_free (function_name);
 +    return FALSE;
 +  }
 +#if 0
 +  if (frame->constant_pool_buffer)
 +    script->constant_pool = swfdec_buffer_ref (frame->constant_pool_buffer);
 +#endif
 +  script->flags = flags;
 +  script->n_registers = n_registers;
 +  script->n_arguments = n_args;
 +  script->arguments = args;
 +
 +  value = vivi_code_function_new (script);
 +  /* attach the function */
 +  if (*function_name == '\0') {
 +    vivi_decompiler_state_push (state, value);
 +  } else {
 +    g_printerr ("FIXME: handle named functions");
 +  }
 +
 +  vivi_decompiler_state_add_pc (state, 3 + len + size);
 +  g_free (function_name);
 +  return TRUE;
 +}
 +
 +static DecompileFunc decompile_funcs[256] = {
 +  [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
 +  [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
 +  [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
 +  [SWFDEC_AS_ACTION_GET_VARIABLE] = vivi_decompile_get_variable,
 +  [SWFDEC_AS_ACTION_SET_VARIABLE] = vivi_decompile_set_variable,
 +  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
 +  [SWFDEC_AS_ACTION_ADD] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_SUBTRACT] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_MULTIPLY] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_DIVIDE] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_EQUALS] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_LESS] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_AND] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_OR] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_STRING_EQUALS] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_STRING_LESS] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_CALL_FUNCTION] = vivi_decompile_call_function,
 +  [SWFDEC_AS_ACTION_ADD2] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_LESS2] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_EQUALS2] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_PUSH_DUPLICATE] = vivi_decompile_duplicate,
 +  [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
 +  [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
 +  [SWFDEC_AS_ACTION_CALL_METHOD] = vivi_decompile_call_method,
 +  [SWFDEC_AS_ACTION_BIT_AND] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_BIT_OR] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_BIT_XOR] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_BIT_LSHIFT] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_BIT_RSHIFT] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_BIT_URSHIFT] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_STRICT_EQUALS] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_GREATER] = vivi_decompile_binary,
 +  [SWFDEC_AS_ACTION_STRING_GREATER] = vivi_decompile_binary,
 +
 +  [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
 +  [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
 +  [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
 +  [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
 +  [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
 +  [SWFDEC_AS_ACTION_DEFINE_FUNCTION2] = NULL, /* handled directly */
 +  [SWFDEC_AS_ACTION_DEFINE_FUNCTION] = NULL, /* handled directly */
 +};
 +
 +static gboolean
 +vivi_decompiler_process (GList **blocks, ViviDecompilerBlock *block, 
 +    ViviDecompilerState *state, guint code, const guint8 *data, guint len)
 +{
 +  gboolean result;
 +
 +  switch (code) {
 +    case SWFDEC_AS_ACTION_DEFINE_FUNCTION:
 +    case SWFDEC_AS_ACTION_DEFINE_FUNCTION2:
 +      return vivi_decompile_define_function (block, state, code, data, len);
 +    case SWFDEC_AS_ACTION_IF:
 +      {
 +	ViviDecompilerBlock *next, *branch;
 +	ViviCodeValue *val;
 +	ViviDecompilerState *new;
 +	gint16 offset;
 +
 +	vivi_decompiler_state_add_pc (state, 5);
 +	if (len != 2) {
 +	  vivi_decompiler_block_add_error (block, state, "If action length invalid (is %u, should be 2)", len);
 +	  vivi_decompiler_block_finish (block, state);
 +	  return TRUE;
 +	}
 +	offset = data[0] | (data[1] << 8);
 +	val = vivi_decompiler_state_pop (state);
 +	vivi_decompiler_block_finish (block, state);
 +	new = vivi_decompiler_state_copy (state);
 +	next = vivi_decompiler_push_block_for_state (blocks, new);
 +	new = vivi_decompiler_state_copy (state);
 +	vivi_decompiler_state_add_pc (new, offset);
 +	branch = vivi_decompiler_push_block_for_state (blocks, new);
 +	if (vivi_decompiler_block_is_finished (block)) {
 +	  vivi_decompiler_block_set_next (block, next);
 +	  vivi_decompiler_block_set_branch (block, branch, val);
 +	}
 +	g_object_unref (val);
 +      }
 +      return FALSE;
 +    case SWFDEC_AS_ACTION_JUMP:
 +      {
 +	ViviDecompilerBlock *next;
 +	ViviDecompilerState *new;
 +	gint16 offset;
 +
 +	vivi_decompiler_state_add_pc (state, 5);
 +	if (len != 2) {
 +	  vivi_decompiler_block_add_error (block, state, "Jump action length invalid (is %u, should be 2)", len);
 +	  vivi_decompiler_block_finish (block, state);
 +	  return FALSE;
 +	}
 +	offset = data[0] | (data[1] << 8);
 +	vivi_decompiler_block_finish (block, state);
 +	new = vivi_decompiler_state_copy (state);
 +	vivi_decompiler_state_add_pc (new, offset);
 +	next = vivi_decompiler_push_block_for_state (blocks, new);
 +	if (vivi_decompiler_block_is_finished (block)) {
 +	  vivi_decompiler_block_set_next (block, next);
 +	}
 +      }
 +      return FALSE;
 +    default:
 +      if (decompile_funcs[code]) {
 +	result = decompile_funcs[code] (block, state, code, data, len);
 +      } else {
 +	vivi_decompiler_block_add_warning (block, "unknown bytecode 0x%02X %u", code, code);
 +	result = TRUE;
 +      }
 +      if (data)
 +	vivi_decompiler_state_add_pc (state, 3 + len);
 +      else
 +	vivi_decompiler_state_add_pc (state, 1);
 +      return result;
 +  };
 +
 +  return TRUE;
 +}
 +
 +static GList *
 +vivi_decompiler_block_decompile (GList *blocks, ViviDecompilerBlock *block, SwfdecScript *script)
 +{
 +  ViviDecompilerState *state;
 +  ViviDecompilerBlock *next_block;
 +  GList *list;
 +  const guint8 *pc, *start, *end, *exit;
 +  const guint8 *data;
 +  guint code, len;
 +
 +  start = script->buffer->data;
 +  end = start + script->buffer->length;
 +  state = vivi_decompiler_state_copy (vivi_decompiler_block_get_start_state (block));
 +  exit = script->exit;
 +  list = g_list_find (blocks, block);
 +  if (list->next) {
 +    next_block = list->next->data;
 +    exit = vivi_decompiler_block_get_start (next_block);
 +  } else {
 +    next_block = NULL;
 +  }
 +
 +  while ((pc = vivi_decompiler_state_get_pc (state)) != exit) {
 +    if (pc < start || pc >= end) {
 +      vivi_decompiler_block_add_error (block, state, "program counter out of range");
 +      goto error;
 +    }
 +    code = pc[0];
 +    if (code & 0x80) {
 +      if (pc + 2 >= end) {
 +	vivi_decompiler_block_add_error (block, state, "bytecode %u length value out of range", code);
 +	goto error;
 +      }
 +      data = pc + 3;
 +      len = pc[1] | pc[2] << 8;
 +      if (data + len > end) {
 +	vivi_decompiler_block_add_error (block, state, "bytecode %u length %u out of range", code, len);
 +	goto error;
 +      }
 +    } else {
 +      data = NULL;
 +      len = 0;
 +    }
 +    if (!vivi_decompiler_process (&blocks, block, state, code, data, len))
 +      goto out;
 +  }
 +  vivi_decompiler_block_finish (block, state);
 +  if (next_block) {
 +    vivi_decompiler_block_set_next (block,
 +	vivi_decompiler_push_block_for_state (&blocks, state));
 +  } else {
 +out:
 +error:
 +    vivi_decompiler_state_free (state);
 +  }
 +  return blocks;
 +}
 +
 +/*** PROGRAM STRUCTURE ANALYSIS ***/
 +
 +static ViviDecompilerBlock *
 +vivi_decompiler_find_start_block (GList *list, const guint8 *startpc)
 +{
 +  GList *walk;
 +  
 +  for (walk = list; walk; walk = walk->next) {
 +    ViviDecompilerBlock *block = walk->data;
 +
 +    if (vivi_decompiler_block_get_start (block) == startpc)
 +      return block;
 +  }
 +  g_assert_not_reached ();
 +  return NULL;
 +}
 +
 +#define ASSERT_BLOCK_LIST(list) \
 +  { \
 +    GList *_walk; \
 +    for (_walk = list; _walk; _walk = _walk->next) { \
 +      ViviDecompilerBlock *_block = _walk->data; \
 +      g_assert (_block->next == NULL || g_list_find (list, _block->next)); \
 +      g_assert (_block->branch == NULL || g_list_find (list, _block->branch)); \
 +    } \
 +  }
 +
 +static ViviCodeStatement *
 +vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
 +{
 +  ViviCodeBlock *block;
 +  ViviDecompilerBlock *current, *next;
 +  GList *ordered, *walk;
 +
 +  //ASSERT_BLOCK_LIST (list);
 +  current = vivi_decompiler_find_start_block (list, startpc);
 +
 +  ordered = NULL;
 +  while (current) {
 +    g_assert (g_list_find (list, current));
 +    list = g_list_remove (list, current);
 +    ordered = g_list_prepend (ordered, current);
 +    next = vivi_decompiler_block_get_branch (current);
 +    if (next)
 +      vivi_decompiler_block_force_label (next);
 +    next = vivi_decompiler_block_get_next (current);
 +    if (next == NULL || !g_list_find (list, next)) {
 +      if (next)
 +	vivi_decompiler_block_force_label (next);
 +      next = list ? list->data : NULL;
 +    }
 +    current = next;
 +  }
 +  g_assert (list == NULL);
 +  ordered = g_list_reverse (ordered);
 +
 +  block = VIVI_CODE_BLOCK (vivi_code_block_new ());
 +  for (walk = ordered; walk; walk = walk->next) {
 +    current = walk->data;
 +    next = vivi_decompiler_block_get_next (current);
 +    if (walk->next && next == walk->next->data) {
 +      vivi_decompiler_block_add_to_block (current, block);
 +      /* FIXME: somehow remove gotos and block forcing */
 +    } else {
 +      vivi_decompiler_block_add_to_block (current, block);
 +    }
 +    if (next == NULL && walk->next != NULL)
 +      vivi_code_block_add_statement (block, VIVI_CODE_STATEMENT (vivi_code_return_new ()));
 +    vivi_decompiler_block_set_next (current, NULL);
 +    vivi_decompiler_block_set_branch (current, NULL, NULL);
 +  }
 +  g_list_foreach (ordered, (GFunc) g_object_unref, NULL);
 +  g_list_free (ordered);
 +  return VIVI_CODE_STATEMENT (block);
 +}
 +
 +static GList *
 +vivi_decompiler_purge_block (GList *list, ViviDecompilerBlock *block)
 +{
 +  g_assert (vivi_decompiler_block_get_n_incoming (block) == 0);
 +  list = g_list_remove (list, block);
 +  g_object_unref (block);
 +  return list;
 +}
 +
 +/*  ONE
 + *   |              ==>   BLOCK
 + *  TWO
 + */
 +static gboolean
 +vivi_decompiler_merge_lines (GList **list)
 +{
 +  ViviDecompilerBlock *block, *next;
 +  ViviCodeValue *val;
 +  gboolean result;
 +  GList *walk;
 +
 +  result = FALSE;
 +  for (walk = *list; walk; walk = walk->next) {
 +    block = walk->data;
 +
 +    /* This is an if block or so */
 +    if (vivi_decompiler_block_get_branch (block) != NULL)
 +      continue;
 +    /* has no next block */
 +    next = vivi_decompiler_block_get_next (block);
 +    if (next == NULL)
 +      continue;
 +    /* The next block has multiple incoming blocks */
 +    if (vivi_decompiler_block_get_n_incoming (next) != 1)
 +      continue;
 +
 +    vivi_decompiler_block_set_next (block, vivi_decompiler_block_get_next (next));
 +    val = vivi_decompiler_block_get_branch_condition (next);
 +    if (val) {
 +      vivi_decompiler_block_set_branch (block, 
 +	  vivi_decompiler_block_get_branch (next), val);
 +    }
 +    vivi_decompiler_block_set_next (next, NULL);
 +    vivi_decompiler_block_set_branch (next, NULL, NULL);
 +    vivi_decompiler_block_add_state_transition (block, next, VIVI_CODE_BLOCK (block));
 +    vivi_decompiler_block_add_to_block (next, VIVI_CODE_BLOCK (block));
 +    vivi_decompiler_block_finish (block, vivi_decompiler_block_get_start_state (next));
 +    *list = vivi_decompiler_purge_block (*list, next);
 +    result = TRUE;
 +  }
 +
 +  return result;
 +}
 +
 +/*      DUP
 + *     (NOT)
 + *     BLOCK
 + *    /   |
 + *[ANDOR] |
 + *    \   |
 + *     NEXT
 + */
 +static gboolean
 +vivi_decompiler_merge_andor (GList **list)
 +{
 +  ViviDecompilerBlock *block, *andor, *next;
 +  gboolean result;
 +  const char *type;
 +  ViviCodeValue *value, *value2;
 +  ViviDecompilerState *state;
 +
 +  GList *walk;
 +  result = FALSE;
 +  for (walk = *list; walk; walk = walk->next) {
 +    block = walk->data;
 +
 +    next = vivi_decompiler_block_get_branch (block);
 +    andor = vivi_decompiler_block_get_next (block);
 +
 +    /* not an if block */
 +    if (andor == NULL)
 +      continue;
 +
 +    /* not an && or || block */
 +    if (vivi_decompiler_block_get_n_incoming (andor) > 1 ||
 +	next != vivi_decompiler_block_get_next (andor) ||
 +	vivi_decompiler_block_get_branch (andor) != NULL)
 +      continue;
 +    /* extract the value */
 +    value = vivi_decompiler_block_get_branch_condition (block);
 +    if (VIVI_IS_CODE_UNARY (value)) {
 +      value = vivi_code_unary_get_value (VIVI_CODE_UNARY (value));
 +      type = "&&";
 +    } else {
 +      type = "||";
 +    }
 +    if (!VIVI_IS_DECOMPILER_DUPLICATE (value))
 +      continue;
 +    value = vivi_decompiler_duplicate_get_value (VIVI_DECOMPILER_DUPLICATE (value));
 +    /* check the extracted value is the only statement in the and/or block */
 +    switch (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (andor))) {
 +      case 0:
 +	break;
 +      case 1:
 +	{
 +	  ViviCodeStatement *stmt = vivi_code_block_get_statement (VIVI_CODE_BLOCK (andor), 0);
 +	  if (!VIVI_IS_CODE_VALUE_STATEMENT (stmt))
 +	    continue;
 +	  if (value != vivi_code_value_statement_get_value (VIVI_CODE_VALUE_STATEMENT (stmt)))
 +	    continue;
 +	}
 +	break;
 +      default:
 +	continue;
 +    }
 +    value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_end_state (block), 0);
 +    if (value != value2)
 +      continue;
 +    value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_end_state (andor), 0);
 +    if (value2 == NULL)
 +      continue;
 +
 +    /* setting code starts here */
 +    DEBUG ("merging %s code for %p\n", type, vivi_decompiler_block_get_start (andor));
 +
 +    /* update our finish state */
 +    value = vivi_code_binary_new_name (value, value2, type);
 +    state = (ViviDecompilerState *) vivi_decompiler_block_get_end_state (block);
 +    g_object_unref (vivi_decompiler_state_pop (state));
 +    vivi_decompiler_state_push (state, value);
 +    /* get rid of the and/or block */
 +    vivi_decompiler_block_set_branch (block, NULL, NULL);
 +    vivi_decompiler_block_set_next (block, next);
 +    *list = vivi_decompiler_purge_block (*list, andor);
 +    /* possibly update the start state of the next block */
 +    if (vivi_decompiler_block_get_n_incoming (next) == 1) {
 +      value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_start_state (next), 0);
 +      if (VIVI_IS_DECOMPILER_UNKNOWN (value2) &&
 +	  vivi_decompiler_unknown_get_block (VIVI_DECOMPILER_UNKNOWN (value2)) == next) {
 +	vivi_decompiler_unknown_set_value (VIVI_DECOMPILER_UNKNOWN (value2), value);
 +      }
 +    }
 +    return TRUE;
 +  }
 +  return FALSE;
 +}
 +
 +/*     COND
 + *    /    \
 + *  [IF] [ELSE]     ==>   BLOCK
 + *    \    /
 + *     NEXT
 + */
 +static gboolean
 +vivi_decompiler_merge_if (GList **list)
 +{
 +  ViviDecompilerBlock *block, *if_block, *else_block, *next;
 +  ViviCodeBlock *b;
 +  ViviCodeIf *if_stmt;
 +  ViviCodeStatement *stmt;
 +  gboolean result;
 +  GList *walk;
 +
 +  result = FALSE;
 +  for (walk = *list; walk; walk = walk->next) {
 +    block = walk->data;
 +
 +    if_block = vivi_decompiler_block_get_branch (block);
 +    else_block = vivi_decompiler_block_get_next (block);
 +    /* not an if block */
 +    if (if_block == NULL)
 +      continue;
 +    /* one of the blocks doesn't exist */
 +    if (if_block == vivi_decompiler_block_get_next (else_block)) 
 +      if_block = NULL;
 +    else if (else_block == vivi_decompiler_block_get_next (if_block))
 +      else_block = NULL;
 +    /* if in if in if in if... */
 +    if ((else_block && vivi_decompiler_block_get_branch (else_block)) || 
 +	(if_block && vivi_decompiler_block_get_branch (if_block)))
 +      continue;
 +    /* if other blocks reference the blocks, bail, there's loops involved */
 +    if ((else_block && vivi_decompiler_block_get_n_incoming (else_block) > 1) ||
 +	(if_block && vivi_decompiler_block_get_n_incoming (if_block) > 1))
 +      continue;
 +    /* if both blocks exist, they must have the same exit block */
 +    if (if_block && else_block && 
 +	vivi_decompiler_block_get_next (if_block) != vivi_decompiler_block_get_next (else_block))
 +      continue;
 +
 +    /* FINALLY we can merge the blocks */
 +    if_stmt = VIVI_CODE_IF (vivi_code_if_new (vivi_decompiler_block_get_branch_condition (block)));
 +    vivi_decompiler_block_set_branch (block, NULL, NULL);
 +    next = vivi_decompiler_block_get_next (if_block ? if_block : else_block);
 +    vivi_decompiler_block_set_next (block, next);
 +    /* assign the if block */
 +    b = VIVI_CODE_BLOCK (vivi_code_block_new ());
 +    if (if_block) {
 +      vivi_decompiler_block_set_next (if_block, NULL);
 +      vivi_decompiler_block_set_branch (if_block, NULL, NULL);
 +      vivi_decompiler_block_add_to_block (if_block, b);
 +      if (next)
 +	vivi_decompiler_block_add_state_transition (if_block, next, b);
 +      *list = vivi_decompiler_purge_block (*list, if_block);
 +    } else {
 +      if (next)
 +	vivi_decompiler_block_add_state_transition (block, next, b);
 +    }
 +    stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (b));
 +    g_object_unref (b);
 +    if (stmt) {
 +      vivi_code_if_set_if (if_stmt, stmt);
 +      g_object_unref (stmt);
 +    }
 +    /* assign the else block */
 +    b = VIVI_CODE_BLOCK (vivi_code_block_new ());
 +    if (else_block) {
 +      vivi_decompiler_block_set_next (else_block, NULL);
 +      vivi_decompiler_block_set_branch (else_block, NULL, NULL);
 +      vivi_decompiler_block_add_to_block (else_block, b);
 +      if (next)
 +	vivi_decompiler_block_add_state_transition (else_block, next, b);
 +      *list = vivi_decompiler_purge_block (*list, else_block);
 +    } else {
 +      if (next)
 +	vivi_decompiler_block_add_state_transition (block, next, b);
 +    }
 +    stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (b));
 +    g_object_unref (b);
 +    if (stmt) {
 +      vivi_code_if_set_else (if_stmt, stmt);
 +      g_object_unref (stmt);
 +    }
 +    /* finally finish the if statement */
 +    stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (if_stmt));
 +    g_object_unref (if_stmt);
 +    if (stmt) {
 +      vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
 +      g_object_unref (stmt);
 +    }
 +    if (next)
 +      vivi_decompiler_block_finish (block, vivi_decompiler_block_get_start_state (next));
 +    result = TRUE;
 +  }
 +
 +  return result;
 +}
 +
 +static ViviCodeStatement *vivi_decompiler_merge_blocks (GList *blocks,
 +    const guint8 *startpc);
 +
 +static gboolean
 +vivi_decompiler_merge_loops (GList **list)
 +{
 +  ViviDecompilerBlock *end, *start, *block, *next;
 +  ViviCodeBlock *body;
 +  gboolean result;
 +  GList *walk, *walk2;
 +  const guint8 *loop_start, *loop_end;
 +  GList *contained, *to_check;
 +  ViviCodeStatement *loop, *stmt;
 +  guint len;
 +
 +  result = FALSE;
 +  for (walk = *list; walk; walk = walk->next) {
 +    end = walk->data;
 +    /* noone has a branch at the end of a loop */
 +    if (vivi_decompiler_block_get_branch (end))
 +      continue;
 +    start = vivi_decompiler_block_get_next (end);
 +    /* block that just returns - no loop at all */
 +    if (start == NULL)
 +      continue;
 +    /* not a jump backwards, so no loop end */
 +    if (vivi_decompiler_block_get_start (start) >
 +	vivi_decompiler_block_get_start (end))
 +      continue;
 +    /* We've found that "end" is a jump backwards. Now, this can be 3 things:
 +     * a) the end of a loop
 +     *    Woohoo, we've found our loop end.
 +     * b) a "continue" statement
 +     *    Wait, we need to find where the lop ends!
 +     * c) a goto backwards
 +     *    Whoops, we need to cleanly exit this loop!
 +     * In case a) and b), "start" will already be correct. So we'll assume that
 +     * it is and go from there.
 +     */
 +    loop_start = vivi_decompiler_block_get_start (start);
 +    /* this is just a rough guess for now */
 +    loop_end = vivi_decompiler_block_get_start (end);
 +    /* let's find the rest of the loop */
 +    to_check = g_list_prepend (NULL, start);
 +    contained = NULL;
 +    while (to_check) {
 +      block = to_check->data;
 +      to_check = g_list_remove (to_check, block);
 +      /* jump to before start?! */
 +      if (vivi_decompiler_block_get_start (block) < loop_start) {
 +	g_list_free (contained);
 +	g_list_free (to_check);
 +	goto failed;
 +      }
 +      /* found a new end of the loop */
 +      if (vivi_decompiler_block_get_start (block) > loop_end) {
 +	ViviDecompilerBlock *swap;
 +	loop_end = vivi_decompiler_block_get_start (block);
 +	swap = block;
 +	block = end;
 +	end = swap;
 +      }
 +      contained = g_list_prepend (contained, block);
 +      next = vivi_decompiler_block_get_next (block);
 +      if (next && next != end && 
 +	  !g_list_find (contained, next) && 
 +          !g_list_find (to_check, next))
 +	to_check = g_list_prepend (to_check, next);
 +      next = vivi_decompiler_block_get_branch (block);
 +      if (next && next != end && 
 +	  !g_list_find (contained, next) && 
 +          !g_list_find (to_check, next))
 +	to_check = g_list_prepend (to_check, next);
 +    }
 +    contained = g_list_reverse (contained);
 +    contained = g_list_remove (contained, start);
 +    /* now we have:
 +     * contained: contains all the blocks contained in the loop
 +     * start: starting block
 +     * end: end block - where "breaks" go to
 +     */
 +    loop = vivi_code_loop_new ();
 +    /* check if the first block is just a branch, in that case it's the
 +     * loop condition */
 +    if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (start)) == 0 &&
 +	(vivi_decompiler_block_get_branch (start) == end ||
 +	 (vivi_decompiler_block_get_branch (start) &&
 +	  vivi_decompiler_block_get_next (start) == end))) {
 +      if (vivi_decompiler_block_get_branch (start) == end) {
 +	ViviCodeValue *value = vivi_code_unary_new (
 +	    vivi_decompiler_block_get_branch_condition (start), '!');
 +	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop),
 +	    vivi_code_value_optimize (value, SWFDEC_AS_TYPE_BOOLEAN));
 +	g_object_unref (value);
 +      } else {
 +	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop), 
 +	    vivi_decompiler_block_get_branch_condition (start));
 +	vivi_decompiler_block_set_next (start,
 +	    vivi_decompiler_block_get_branch (start));
 +      }
 +      vivi_decompiler_block_set_branch (start, NULL, NULL);
 +      loop_start = vivi_decompiler_block_get_start (
 +	  vivi_decompiler_block_get_next (start));
 +      vivi_code_block_add_statement (VIVI_CODE_BLOCK (start), VIVI_CODE_STATEMENT (loop));
 +      vivi_decompiler_block_set_next (start, end);
 +    } else {
 +      /* FIXME: for (;;) loop */
 +      contained = g_list_prepend (contained, start);
 +      block = vivi_decompiler_block_new (vivi_decompiler_state_copy (
 +	    vivi_decompiler_block_get_start_state (start)));
 +      vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (loop));
 +      for (walk2 = *list; walk2; walk2 = walk2->next) {
 +	if (walk2->data == start) {
 +	  walk2->data = block;
 +	  continue;
 +	}
 +	if (g_list_find (contained, walk2->data))
 +	  continue;
 +	if (vivi_decompiler_block_get_branch (walk2->data) == start)
 +	  vivi_decompiler_block_set_branch (walk2->data, block,
 +	      g_object_ref (vivi_decompiler_block_get_branch_condition (walk2->data)));
 +	if (vivi_decompiler_block_get_next (walk2->data) == start)
 +	  vivi_decompiler_block_set_next (walk2->data, block);
 +      }
 +      vivi_decompiler_block_set_next (block, end);
 +    }
 +
 +    /* break all connections to the outside */
 +    for (walk2 = contained; walk2; walk2 = walk2->next) {
 +      block = walk2->data;
 +      *list = g_list_remove (*list, block);
 +      next = vivi_decompiler_block_get_branch (block);
 +      if (next != NULL && (!g_list_find (contained, next) || next == start)) {
 +	stmt = vivi_code_if_new (g_object_ref (vivi_decompiler_block_get_branch_condition (block)));
 +	if (next == start) {
 +	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_continue_new ());
 +	} else if (next == end) {
 +	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_break_new ());
 +	} else {
 +	  vivi_decompiler_block_force_label (next);
 +	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (vivi_code_goto_new (
 +		VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
 +	}
 +	vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
 +	vivi_decompiler_block_set_branch (block, NULL, NULL);
 +      }
 +      next = vivi_decompiler_block_get_next (block);
 +      if (next != NULL && (!g_list_find (contained, next) || next == start)) {
 +	if (next == start) {
 +	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), vivi_code_continue_new ());
 +	} else if (next == end) {
 +	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), vivi_code_break_new ());
 +	} else {
 +	  vivi_decompiler_block_force_label (next);
 +	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (
 +		vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
 +	}
 +	vivi_decompiler_block_set_next (block, NULL);
 +      }
 +    }
 +    /* break all connections from the outside */
 +    for (walk2 = *list; walk2; walk2 = walk2->next) {
 +      block = walk2->data;
 +      next = vivi_decompiler_block_get_branch (block);
 +      if (next && !g_list_find (*list, next)) {
 +	stmt = vivi_code_if_new (g_object_ref (vivi_decompiler_block_get_branch_condition (block)));
 +	vivi_decompiler_block_force_label (next);
 +	vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (vivi_code_goto_new (
 +	      VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
 +	vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
 +	vivi_decompiler_block_set_branch (block, NULL, NULL);
 +      }
 +      next = vivi_decompiler_block_get_next (block);
 +      if (next && !g_list_find (*list, next)) {
 +	vivi_decompiler_block_force_label (next);
 +	vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (
 +	      vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
 +	vivi_decompiler_block_set_next (block, NULL);
 +      }
 +    }
 +    body = VIVI_CODE_BLOCK (vivi_decompiler_merge_blocks (contained, loop_start));
 +    while ((len = vivi_code_block_get_n_statements (body))) {
 +      stmt = vivi_code_block_get_statement (body, len - 1);
 +      if (VIVI_IS_CODE_CONTINUE (stmt)) {
 +	vivi_code_block_remove_statement (body, stmt);
 +      } else {
 +	break;
 +      }
 +    }
 +    vivi_code_loop_set_statement (VIVI_CODE_LOOP (loop), VIVI_CODE_STATEMENT (body));
 +    g_object_unref (body);
 +    g_object_unref (loop);
 +
 +    return TRUE;
 +failed:
 +    continue;
 +  }
 +  return FALSE;
 +}
 +
 +static ViviCodeStatement *
 +vivi_decompiler_merge_blocks (GList *blocks, const guint8 *startpc)
 +{
 +  gboolean restart;
 +
 +  do {
 +    restart = FALSE;
 +    DEBUG ("merging: %u blocks left\n", g_list_length (blocks));
 +
 +    restart |= vivi_decompiler_merge_lines (&blocks);
 +    if (vivi_decompiler_merge_andor (&blocks)) {
 +      restart = TRUE;
 +      continue;
 +    }
 +    restart |= vivi_decompiler_merge_if (&blocks);
 +    restart |= vivi_decompiler_merge_loops (&blocks);
 +  } while (restart);
 +
 +  return vivi_decompiler_merge_blocks_last_resort (blocks, startpc);
 +}
 +
 +static void
 +vivi_decompiler_dump_graphviz (GList *blocks)
 +{
 +  GString *string;
 +  GList *walk;
 +  const char *filename;
 +
 +  filename = g_getenv ("VIVI_DECOMPILER_DUMP");
 +  if (filename == NULL)
 +    return;
 +
 +  string = g_string_new ("digraph G\n{\n");
 +  g_string_append (string, "  node [ shape = box ]\n");
 +  for (walk = blocks; walk; walk = walk->next) {
 +    g_string_append_printf (string, "  node%p\n", 
 +	vivi_decompiler_block_get_start (walk->data));
 +  }
 +  g_string_append (string, "\n");
 +  for (walk = blocks; walk; walk = walk->next) {
 +    ViviDecompilerBlock *block, *next;
 +
 +    block = walk->data;
 +    next = vivi_decompiler_block_get_next (block);
 +    if (next) {
 +      g_string_append_printf (string, "  node%p -> node%p\n", 
 +	  vivi_decompiler_block_get_start (block),
 +	  vivi_decompiler_block_get_start (next));
 +    }
 +    next = vivi_decompiler_block_get_branch (block);
 +    if (next) {
 +      g_string_append_printf (string, "  node%p -> node%p\n",
 +	  vivi_decompiler_block_get_start (block),
 +	  vivi_decompiler_block_get_start (next));
 +    }
 +  }
 +  g_string_append (string, "}\n");
 +  g_file_set_contents (filename, string->str, string->len, NULL);
 +  g_string_free (string, TRUE);
 +}
 +
 +ViviCodeStatement *
 +vivi_decompile_script (SwfdecScript *script)
 +{
 +  ViviDecompilerBlock *block;
 +  ViviDecompilerState *state;
 +  ViviCodeStatement *stmt;
 +  GList *walk, *blocks;
 +
 +  g_return_val_if_fail (script != NULL, NULL);
 +
 +  DEBUG ("--> starting decompilation\n");
 +  state = vivi_decompiler_state_new (script, script->main, 4);
 +  if (script->constant_pool) {
 +    vivi_decompiler_state_set_constant_pool (state,
- 	swfdec_constant_pool_new_from_action (script->constant_pool->data,
- 	    script->constant_pool->length, script->version));
++	swfdec_constant_pool_new (NULL, script->constant_pool, script->version));
 +  }
 +  block = vivi_decompiler_block_new (state);
 +  blocks = g_list_prepend (NULL, block);
 +  while (TRUE) {
 +    for (walk = blocks; walk; walk = walk->next) {
 +      block = walk->data;
 +      if (!vivi_decompiler_block_is_finished (block))
 +	break;
 +    }
 +    if (walk == NULL)
 +      break;
 +    blocks = vivi_decompiler_block_decompile (blocks, block, script);
 +  }
 +  DEBUG ("--- decompilation done, starting optimization\n");
 +
 +  vivi_decompiler_dump_graphviz (blocks);
 +  stmt = vivi_decompiler_merge_blocks (blocks, script->main);
 +  DEBUG ("<-- optimization done\n");
 +  return stmt;
 +}
 +
diff --cc vivified/code/vivi_decompiler_state.c
index a6d93d5,0000000..f022b07
mode 100644,000000..100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@@ -1,201 -1,0 +1,201 @@@
 +/* Vivified
 + * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + * 
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + * 
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 + * Boston, MA  02110-1301  USA
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#include <swfdec/swfdec_script_internal.h>
 +
 +#include "vivi_decompiler_state.h"
 +#include "vivi_code_constant.h"
 +#include "vivi_decompiler_unknown.h"
 +
 +struct _ViviDecompilerState {
 +  SwfdecScript *	script;
 +  const guint8 *	pc;
 +  ViviCodeValue **	registers;
 +  guint			n_registers;
 +  GSList *		stack;
 +  SwfdecConstantPool *	pool;
 +};
 +
 +void
 +vivi_decompiler_state_free (ViviDecompilerState *state)
 +{
 +  guint i;
 +
 +  for (i = 0; i < state->n_registers; i++) {
 +    if (state->registers[i])
 +      g_object_unref (state->registers[i]);
 +  }
 +  g_slice_free1 (sizeof (ViviCodeValue *) * state->n_registers, state->registers);
 +  g_slist_foreach (state->stack, (GFunc) g_object_unref, NULL);
 +  g_slist_free (state->stack);
 +  if (state->pool)
-     swfdec_constant_pool_free (state->pool);
++    swfdec_constant_pool_unref (state->pool);
 +  swfdec_script_unref (state->script);
 +  g_slice_free (ViviDecompilerState, state);
 +}
 +
 +ViviDecompilerState *
 +vivi_decompiler_state_new (SwfdecScript *script, const guint8 *pc, guint n_registers)
 +{
 +  ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
 +
 +  state->script = swfdec_script_ref (script);
 +  state->pc = pc;
 +  state->registers = g_slice_alloc0 (sizeof (ViviCodeValue *) * n_registers);
 +  state->n_registers = n_registers;
 +
 +  return state;
 +}
 +
 +void
 +vivi_decompiler_state_push (ViviDecompilerState *state, ViviCodeValue *val)
 +{
 +  state->stack = g_slist_prepend (state->stack, val);
 +}
 +
 +ViviCodeValue *
 +vivi_decompiler_state_pop (ViviDecompilerState *state)
 +{
 +  if (state->stack == NULL) {
 +    return VIVI_CODE_VALUE (vivi_code_constant_new_undefined ());
 +  } else {
 +    ViviCodeValue *pop;
 +    pop = state->stack->data;
 +    state->stack = g_slist_remove (state->stack, pop);
 +    return pop;
 +  }
 +}
 +
 +guint
 +vivi_decompiler_state_get_stack_depth (const ViviDecompilerState *state)
 +{
 +  g_return_val_if_fail (state != NULL, 0);
 +
 +  return g_slist_length (state->stack);
 +}
 +
 +ViviCodeValue *
 +vivi_decompiler_state_peek_nth (const ViviDecompilerState *state, guint i)
 +{
 +  g_return_val_if_fail (state != NULL, NULL);
 +
 +  return g_slist_nth_data (state->stack, i);
 +}
 +
 +ViviDecompilerState *
 +vivi_decompiler_state_copy (const ViviDecompilerState *src)
 +{
 +  ViviDecompilerState *dest;
 +  guint i;
 +
 +  dest = vivi_decompiler_state_new (src->script, src->pc, src->n_registers);
 +  for (i = 0; i < src->n_registers; i++) {
 +    if (src->registers[i])
 +      dest->registers[i] = g_object_ref (src->registers[i]);
 +  }
 +  dest->stack = g_slist_copy (src->stack);
 +  g_slist_foreach (dest->stack, (GFunc) g_object_ref, NULL);
 +  if (src->pool)
-     dest->pool = swfdec_constant_pool_copy (src->pool);
++    dest->pool = swfdec_constant_pool_ref (src->pool);
 +
 +  return dest;
 +}
 +
 +ViviCodeValue *
 +vivi_decompiler_state_get_register (const ViviDecompilerState *state, guint reg)
 +{
 +  if (reg >= state->n_registers || state->registers[reg] == NULL)
 +    return VIVI_CODE_VALUE (vivi_code_constant_new_undefined ());
 +  else
 +    return g_object_ref (state->registers[reg]);
 +}
 +
 +const guint8 *
 +vivi_decompiler_state_get_pc (const ViviDecompilerState *state)
 +{
 +  return state->pc;
 +}
 +
 +void
 +vivi_decompiler_state_add_pc (ViviDecompilerState *state, int diff)
 +{
 +  state->pc += diff;
 +}
 +
 +SwfdecScript *
 +vivi_decompiler_state_get_script (const ViviDecompilerState *state)
 +{
 +  return state->script;
 +}
 +
 +const SwfdecConstantPool *
 +vivi_decompiler_state_get_constant_pool (const ViviDecompilerState *state)
 +{
 +  return state->pool;
 +}
 +
 +void
 +vivi_decompiler_state_set_constant_pool (ViviDecompilerState *state, 
 +    SwfdecConstantPool *pool)
 +{
 +  if (state->pool)
-     swfdec_constant_pool_free (state->pool);
++    swfdec_constant_pool_unref (state->pool);
 +  state->pool = pool;
 +}
 +
 +guint
 +vivi_decompiler_state_get_version (const ViviDecompilerState *state)
 +{
 +  return swfdec_script_get_version (state->script);
 +}
 +
 +gboolean
 +vivi_decompiler_state_is_compatible (const ViviDecompilerState *a, const ViviDecompilerState *b)
 +{
 +  g_return_val_if_fail (a != NULL, FALSE);
 +  g_return_val_if_fail (b != NULL, FALSE);
 +
 +  if (a->n_registers != b->n_registers)
 +    return FALSE;
 +  /* FIXME: check registers */
 +  if (a->pool || b->pool) {
 +    guint i, len;
 +
 +    if (a->pool == NULL || b->pool == NULL)
 +      return FALSE;
 +    len = swfdec_constant_pool_size (a->pool);
 +    if (len != swfdec_constant_pool_size (b->pool))
 +      return FALSE;
 +    for (i = 0; i < len; i++) {
 +      if (!g_str_equal (swfdec_constant_pool_get (a->pool, i),
 +	    swfdec_constant_pool_get (b->pool, i)))
 +	return FALSE;
 +    }
 +  }
 +  /* FIXME: is this necessary? */
 +  if (g_slist_length (a->stack) != g_slist_length (b->stack))
 +    return FALSE;
 +
 +  return TRUE;
 +}
 +
commit 9f34b0eb5ab713b9badba9082535d076453d1fb1
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Mar 24 22:04:14 2008 +0100

    decompile function definitions
    
    contains lots of changes:
    - ViviDecompiler object gone
    - errors abort decompilation
    
    Does not handle constant pools properly yet

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 3fda037..1148938 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -13,6 +13,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_comment.c \
 	vivi_code_constant.c \
 	vivi_code_continue.c \
+	vivi_code_function.c \
 	vivi_code_function_call.c \
 	vivi_code_get.c \
 	vivi_code_get_url.c \
@@ -43,6 +44,7 @@ noinst_HEADERS = \
 	vivi_code_comment.h \
 	vivi_code_constant.h \
 	vivi_code_continue.h \
+	vivi_code_function.h \
 	vivi_code_function_call.h \
 	vivi_code_get.h \
 	vivi_code_get_url.h \
diff --git a/vivified/code/decompiler.c b/vivified/code/decompiler.c
index 3449cb3..146f4f4 100644
--- a/vivified/code/decompiler.c
+++ b/vivified/code/decompiler.c
@@ -28,27 +28,24 @@
 #include <swfdec/swfdec_sprite_movie.h>
 #include <swfdec/swfdec_swf_decoder.h>
 
+#include "vivi_code_function.h"
 #include "vivi_code_text_printer.h"
-#include "vivi_decompiler.h"
 
 static void
 decode_script (gpointer offset, gpointer scriptp, gpointer unused)
 {
   SwfdecScript *script = scriptp;
-  ViviDecompiler *dec = vivi_decompiler_new (scriptp);
-  ViviCodeToken *token;
+  ViviCodeValue *fun;
   ViviCodePrinter *printer;
 
   g_print ("/* %s */\n", script->name);
-  token = VIVI_CODE_TOKEN (vivi_decompiler_get_block (dec));
+  fun = vivi_code_function_new (scriptp);
   printer = vivi_code_text_printer_new ();
-  g_print ("{\n");
-  vivi_code_printer_push_indentation (printer);
-  vivi_code_printer_print_token (printer, token);
-  vivi_code_printer_pop_indentation (printer);
-  g_print ("}\n\n");
+
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (fun));
+
   g_object_unref (printer);
-  g_object_unref (dec);
+  g_object_unref (fun);
 }
 
 int 
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index f6c2d03..f3f3237 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -34,6 +34,7 @@
 #include "vivi_code_break.h"
 #include "vivi_code_constant.h"
 #include "vivi_code_continue.h"
+#include "vivi_code_function.h"
 #include "vivi_code_function_call.h"
 #include "vivi_code_get.h"
 #include "vivi_code_get_url.h"
@@ -49,20 +50,20 @@
 #include "vivi_decompiler_state.h"
 #include "vivi_decompiler_unknown.h"
 
-#if 0
+#if 1
 #define DEBUG g_printerr
 #else
 #define DEBUG(...)
 #endif
 
-#if 0
+#if 1
 static G_GNUC_UNUSED void
-DUMP_BLOCKS (ViviDecompiler *dec)
+DUMP_BLOCKS (GList *blocks)
 {
   GList *walk;
 
   g_print ("dumping blocks:\n");
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = blocks; walk; walk = walk->next) {
     ViviDecompilerBlock *block = walk->data;
     g_printerr ("  %p -> %p\n", vivi_decompiler_block_get_start (block), 
 	block->end ? vivi_decompiler_state_get_pc (block->end) : NULL);
@@ -73,7 +74,7 @@ DUMP_BLOCKS (ViviDecompiler *dec)
 #endif
 
 static ViviDecompilerBlock *
-vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *state)
+vivi_decompiler_push_block_for_state (GList **blocks, ViviDecompilerState *state)
 {
   ViviDecompilerBlock *block;
   GList *walk;
@@ -81,8 +82,8 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 
   pc = vivi_decompiler_state_get_pc (state);
   DEBUG ("pc: %p\n", pc);
-  DUMP_BLOCKS (dec);
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  DUMP_BLOCKS (*blocks);
+  for (walk = *blocks; walk; walk = walk->next) {
     block = walk->data;
     block_start = vivi_decompiler_block_get_start (block);
     if (block_start < pc) {
@@ -111,7 +112,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 
   /* FIXME: see if the block is already there! */
   block = vivi_decompiler_block_new (state);
-  dec->blocks = g_list_insert_before (dec->blocks, walk, block);
+  *blocks = g_list_insert_before (*blocks, walk, block);
   return block;
 }
 
@@ -136,8 +137,8 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 	{
 	  char *s = swfdec_bits_get_string (&bits, vivi_decompiler_state_get_version (state));
 	  if (s == NULL) {
-	    vivi_decompiler_block_add_error (block, "could not read string");
-	    return TRUE;
+	    vivi_decompiler_block_add_error (block, state, "could not read string");
+	    return FALSE;
 	  }
 	  val = vivi_code_constant_new_string (s);
 	  g_free (s);
@@ -171,11 +172,11 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
 	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
 	  if (pool == NULL) {
-	    vivi_decompiler_block_add_error (block, "no constant pool to push from");
+	    vivi_decompiler_block_add_error (block, state, "no constant pool to push from");
 	    return TRUE;
 	  }
 	  if (i >= swfdec_constant_pool_size (pool)) {
-	    vivi_decompiler_block_add_error (block, "constant pool index %u too high - only %u elements",
+	    vivi_decompiler_block_add_error (block, state, "constant pool index %u too high - only %u elements",
 		i, swfdec_constant_pool_size (pool));
 	    return TRUE;
 	  }
@@ -183,7 +184,7 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 	  break;
 	}
       default:
-	vivi_decompiler_block_add_error (block, "Push: type %u not implemented", type);
+	vivi_decompiler_block_add_error (block, state, "Push: type %u not implemented", type);
 	return TRUE;
     }
     vivi_decompiler_state_push (state, val);
@@ -251,7 +252,7 @@ vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
   url = vivi_decompiler_state_pop (state);
 
   if (len != 1) {
-    vivi_decompiler_block_add_error (block, "invalid length in getURL2 command");   
+    vivi_decompiler_block_add_error (block, state, "invalid length in getURL2 command");   
   } else {
     ViviCodeStatement *stmt;
     guint method = data[0] & 3;
@@ -387,7 +388,7 @@ vivi_decompile_function_call (ViviDecompilerBlock *block, ViviDecompilerState *s
   if (!VIVI_IS_CODE_CONSTANT (args) || 
       vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (args)) != SWFDEC_AS_TYPE_NUMBER ||
       ((count = d = vivi_code_constant_get_number (VIVI_CODE_CONSTANT (args))) != d)) {
-    vivi_decompiler_block_add_error (block, "could not determine function argument count");
+    vivi_decompiler_block_add_error (block, state, "could not determine function argument count");
     g_object_unref (args);
     g_object_unref (call);
     return FALSE;
@@ -429,6 +430,120 @@ vivi_decompile_call_method (ViviDecompilerBlock *block, ViviDecompilerState *sta
   return vivi_decompile_function_call (block, state, value, name, args);
 }
 
+static gboolean
+vivi_decompile_define_function (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *value;
+  char *function_name;
+  const char *name = NULL;
+  guint i, n_args, size, n_registers;
+  SwfdecBits bits;
+  SwfdecBuffer *buffer;
+  SwfdecScript *script;
+  guint flags = 0;
+  SwfdecScriptArgument *args;
+  gboolean v2 = (code == 0x8e);
+
+  swfdec_bits_init_data (&bits, data, len);
+  script = vivi_decompiler_state_get_script (state);
+  function_name = swfdec_bits_get_string (&bits, script->version);
+  if (function_name == NULL) {
+    vivi_decompiler_block_add_error (block, state, "could not parse function name");
+    return FALSE;
+  }
+  n_args = swfdec_bits_get_u16 (&bits);
+  if (v2) {
+    n_registers = swfdec_bits_get_u8 (&bits);
+    if (n_registers == 0)
+      n_registers = 4;
+    flags = swfdec_bits_get_u16 (&bits);
+  } else {
+    n_registers = 5;
+  }
+  if (n_args) {
+    args = g_new0 (SwfdecScriptArgument, n_args);
+    for (i = 0; i < n_args && swfdec_bits_left (&bits); i++) {
+      if (v2) {
+	args[i].preload = swfdec_bits_get_u8 (&bits);
+	if (args[i].preload && args[i].preload >= n_registers) {
+	  vivi_decompiler_block_add_error (block, state, 
+	      "argument %u cannot be preloaded into register %u out of %u", 
+	      i, args[i].preload, n_registers);
+	  /* FIXME: figure out correct error handling here */
+	  args[i].preload = 0;
+	}
+      }
+      args[i].name = swfdec_bits_get_string (&bits, script->version);
+      if (args[i].name == NULL || args[i].name == '\0') {
+	vivi_decompiler_block_add_error (block, state, "empty argument name not allowed");
+	g_free (args);
+	return FALSE;
+      }
+      /* FIXME: check duplicate arguments */
+    }
+  } else {
+    args = NULL;
+  }
+  size = swfdec_bits_get_u16 (&bits);
+  buffer = script->buffer;
+  /* check the script can be created */
+  if (vivi_decompiler_state_get_pc (state) + 3 + len + size > buffer->data + buffer->length) {
+    vivi_decompiler_block_add_error (block, state, "size of function is too big");
+    g_free (args);
+    g_free (function_name);
+    return FALSE;
+  }
+  /* create the script */
+  buffer = swfdec_buffer_new_subbuffer (buffer, 
+      vivi_decompiler_state_get_pc (state) + 3 + len - buffer->data, size);
+  swfdec_bits_init (&bits, buffer);
+  if (*function_name) {
+    name = function_name;
+  } else if (vivi_decompiler_state_get_stack_depth (state) > 0) {
+    /* This is kind of a hack that uses a feature of the Adobe compiler:
+     * foo = function () {} is compiled as these actions:
+     * Push "foo", DefineFunction, SetVariable/SetMember
+     * With this knowledge we can inspect the topmost stack member, since
+     * it will contain the name this function will soon be assigned to.
+     */
+    value = vivi_decompiler_state_peek_nth (state, 0);
+    if (VIVI_IS_CODE_CONSTANT (value) &&
+	vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (value)) == SWFDEC_AS_TYPE_STRING)
+      name = SWFDEC_AS_VALUE_GET_STRING (&VIVI_CODE_CONSTANT (value)->value);
+  }
+  if (name == NULL)
+    name = "unnamed_function";
+  script = swfdec_script_new_from_bits (&bits, name, script->version);
+  swfdec_buffer_unref (buffer);
+  if (script == NULL) {
+    vivi_decompiler_block_add_error (block, state, "failed to create script");
+    g_free (args);
+    g_free (function_name);
+    return FALSE;
+  }
+#if 0
+  if (frame->constant_pool_buffer)
+    script->constant_pool = swfdec_buffer_ref (frame->constant_pool_buffer);
+#endif
+  script->flags = flags;
+  script->n_registers = n_registers;
+  script->n_arguments = n_args;
+  script->arguments = args;
+
+  value = vivi_code_function_new (script);
+  /* attach the function */
+  if (*function_name == '\0') {
+    vivi_decompiler_state_push (state, value);
+  } else {
+    g_printerr ("FIXME: handle named functions");
+  }
+
+  vivi_decompiler_state_add_pc (state, 3 + len + size);
+  g_free (function_name);
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
@@ -469,15 +584,20 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
   [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
   [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
+  [SWFDEC_AS_ACTION_DEFINE_FUNCTION2] = NULL, /* handled directly */
+  [SWFDEC_AS_ACTION_DEFINE_FUNCTION] = NULL, /* handled directly */
 };
 
 static gboolean
-vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block, 
+vivi_decompiler_process (GList **blocks, ViviDecompilerBlock *block, 
     ViviDecompilerState *state, guint code, const guint8 *data, guint len)
 {
   gboolean result;
 
   switch (code) {
+    case SWFDEC_AS_ACTION_DEFINE_FUNCTION:
+    case SWFDEC_AS_ACTION_DEFINE_FUNCTION2:
+      return vivi_decompile_define_function (block, state, code, data, len);
     case SWFDEC_AS_ACTION_IF:
       {
 	ViviDecompilerBlock *next, *branch;
@@ -487,7 +607,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 
 	vivi_decompiler_state_add_pc (state, 5);
 	if (len != 2) {
-	  vivi_decompiler_block_add_error (block, "If action length invalid (is %u, should be 2)", len);
+	  vivi_decompiler_block_add_error (block, state, "If action length invalid (is %u, should be 2)", len);
 	  vivi_decompiler_block_finish (block, state);
 	  return TRUE;
 	}
@@ -495,10 +615,10 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	val = vivi_decompiler_state_pop (state);
 	vivi_decompiler_block_finish (block, state);
 	new = vivi_decompiler_state_copy (state);
-	next = vivi_decompiler_push_block_for_state (dec, new);
+	next = vivi_decompiler_push_block_for_state (blocks, new);
 	new = vivi_decompiler_state_copy (state);
 	vivi_decompiler_state_add_pc (new, offset);
-	branch = vivi_decompiler_push_block_for_state (dec, new);
+	branch = vivi_decompiler_push_block_for_state (blocks, new);
 	if (vivi_decompiler_block_is_finished (block)) {
 	  vivi_decompiler_block_set_next (block, next);
 	  vivi_decompiler_block_set_branch (block, branch, val);
@@ -514,7 +634,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 
 	vivi_decompiler_state_add_pc (state, 5);
 	if (len != 2) {
-	  vivi_decompiler_block_add_error (block, "Jump action length invalid (is %u, should be 2)", len);
+	  vivi_decompiler_block_add_error (block, state, "Jump action length invalid (is %u, should be 2)", len);
 	  vivi_decompiler_block_finish (block, state);
 	  return FALSE;
 	}
@@ -522,7 +642,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	vivi_decompiler_block_finish (block, state);
 	new = vivi_decompiler_state_copy (state);
 	vivi_decompiler_state_add_pc (new, offset);
-	next = vivi_decompiler_push_block_for_state (dec, new);
+	next = vivi_decompiler_push_block_for_state (blocks, new);
 	if (vivi_decompiler_block_is_finished (block)) {
 	  vivi_decompiler_block_set_next (block, next);
 	}
@@ -532,7 +652,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
       if (decompile_funcs[code]) {
 	result = decompile_funcs[code] (block, state, code, data, len);
       } else {
-	vivi_decompiler_block_add_error (block, "unknown bytecode 0x%02X %u", code, code);
+	vivi_decompiler_block_add_warning (block, "unknown bytecode 0x%02X %u", code, code);
 	result = TRUE;
       }
       if (data)
@@ -545,8 +665,8 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
   return TRUE;
 }
 
-static void
-vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block)
+static GList *
+vivi_decompiler_block_decompile (GList *blocks, ViviDecompilerBlock *block, SwfdecScript *script)
 {
   ViviDecompilerState *state;
   ViviDecompilerBlock *next_block;
@@ -555,11 +675,11 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
   const guint8 *data;
   guint code, len;
 
-  start = dec->script->buffer->data;
-  end = start + dec->script->buffer->length;
+  start = script->buffer->data;
+  end = start + script->buffer->length;
   state = vivi_decompiler_state_copy (vivi_decompiler_block_get_start_state (block));
-  exit = dec->script->exit;
-  list = g_list_find (dec->blocks, block);
+  exit = script->exit;
+  list = g_list_find (blocks, block);
   if (list->next) {
     next_block = list->next->data;
     exit = vivi_decompiler_block_get_start (next_block);
@@ -569,37 +689,38 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
 
   while ((pc = vivi_decompiler_state_get_pc (state)) != exit) {
     if (pc < start || pc >= end) {
-      vivi_decompiler_block_add_error (block, "program counter out of range");
+      vivi_decompiler_block_add_error (block, state, "program counter out of range");
       goto error;
     }
     code = pc[0];
     if (code & 0x80) {
       if (pc + 2 >= end) {
-	vivi_decompiler_block_add_error (block, "bytecode %u length value out of range", code);
+	vivi_decompiler_block_add_error (block, state, "bytecode %u length value out of range", code);
 	goto error;
       }
       data = pc + 3;
       len = pc[1] | pc[2] << 8;
       if (data + len > end) {
-	vivi_decompiler_block_add_error (block, "bytecode %u length %u out of range", code, len);
+	vivi_decompiler_block_add_error (block, state, "bytecode %u length %u out of range", code, len);
 	goto error;
       }
     } else {
       data = NULL;
       len = 0;
     }
-    if (!vivi_decompiler_process (dec, block, state, code, data, len))
+    if (!vivi_decompiler_process (&blocks, block, state, code, data, len))
       goto out;
   }
   vivi_decompiler_block_finish (block, state);
   if (next_block) {
     vivi_decompiler_block_set_next (block,
-	vivi_decompiler_push_block_for_state (dec, state));
+	vivi_decompiler_push_block_for_state (&blocks, state));
   } else {
 out:
 error:
     vivi_decompiler_state_free (state);
   }
+  return blocks;
 }
 
 /*** PROGRAM STRUCTURE ANALYSIS ***/
@@ -1148,7 +1269,7 @@ vivi_decompiler_merge_blocks (GList *blocks, const guint8 *startpc)
 }
 
 static void
-vivi_decompiler_dump_graphviz (ViviDecompiler *dec)
+vivi_decompiler_dump_graphviz (GList *blocks)
 {
   GString *string;
   GList *walk;
@@ -1160,12 +1281,12 @@ vivi_decompiler_dump_graphviz (ViviDecompiler *dec)
 
   string = g_string_new ("digraph G\n{\n");
   g_string_append (string, "  node [ shape = box ]\n");
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = blocks; walk; walk = walk->next) {
     g_string_append_printf (string, "  node%p\n", 
 	vivi_decompiler_block_get_start (walk->data));
   }
   g_string_append (string, "\n");
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = blocks; walk; walk = walk->next) {
     ViviDecompilerBlock *block, *next;
 
     block = walk->data;
@@ -1187,88 +1308,40 @@ vivi_decompiler_dump_graphviz (ViviDecompiler *dec)
   g_string_free (string, TRUE);
 }
 
-static void
-vivi_decompiler_run (ViviDecompiler *dec)
+ViviCodeStatement *
+vivi_decompile_script (SwfdecScript *script)
 {
   ViviDecompilerBlock *block;
   ViviDecompilerState *state;
   ViviCodeStatement *stmt;
-  GList *walk;
+  GList *walk, *blocks;
 
-  state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
-  if (dec->script->constant_pool) {
+  g_return_val_if_fail (script != NULL, NULL);
+
+  DEBUG ("--> starting decompilation\n");
+  state = vivi_decompiler_state_new (script, script->main, 4);
+  if (script->constant_pool) {
     vivi_decompiler_state_set_constant_pool (state,
-	swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
-	    dec->script->constant_pool->length, dec->script->version));
+	swfdec_constant_pool_new_from_action (script->constant_pool->data,
+	    script->constant_pool->length, script->version));
   }
   block = vivi_decompiler_block_new (state);
-  g_assert (dec->blocks == NULL);
-  dec->blocks = g_list_prepend (dec->blocks, block);
+  blocks = g_list_prepend (NULL, block);
   while (TRUE) {
-    for (walk = dec->blocks; walk; walk = walk->next) {
+    for (walk = blocks; walk; walk = walk->next) {
       block = walk->data;
       if (!vivi_decompiler_block_is_finished (block))
 	break;
     }
     if (walk == NULL)
       break;
-    vivi_decompiler_block_decompile (dec, block);
+    blocks = vivi_decompiler_block_decompile (blocks, block, script);
   }
+  DEBUG ("--- decompilation done, starting optimization\n");
 
-  vivi_decompiler_dump_graphviz (dec);
-  stmt = vivi_decompiler_merge_blocks (dec->blocks, dec->script->main);
-  dec->blocks = g_list_prepend (NULL, stmt);
-}
-
-/*** OBJECT ***/
-
-G_DEFINE_TYPE (ViviDecompiler, vivi_decompiler, G_TYPE_OBJECT)
-
-static void
-vivi_decompiler_dispose (GObject *object)
-{
-  ViviDecompiler *dec = VIVI_DECOMPILER (object);
-
-  if (dec->script) {
-    swfdec_script_unref (dec->script);
-    dec->script = NULL;
-  }
-  g_list_foreach (dec->blocks, (GFunc) g_object_unref, NULL);
-  g_list_free (dec->blocks);
-  dec->blocks = NULL;
-
-  G_OBJECT_CLASS (vivi_decompiler_parent_class)->dispose (object);
-}
-
-static void
-vivi_decompiler_class_init (ViviDecompilerClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = vivi_decompiler_dispose;
-}
-
-static void
-vivi_decompiler_init (ViviDecompiler *dec)
-{
-}
-
-ViviDecompiler *
-vivi_decompiler_new (SwfdecScript *script)
-{
-  ViviDecompiler *dec = g_object_new (VIVI_TYPE_DECOMPILER, NULL);
-
-  dec->script = swfdec_script_ref (script);
-  vivi_decompiler_run (dec);
-
-  return dec;
-}
-
-ViviCodeBlock *
-vivi_decompiler_get_block (ViviDecompiler *dec)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
-
-  return dec->blocks->data;
+  vivi_decompiler_dump_graphviz (blocks);
+  stmt = vivi_decompiler_merge_blocks (blocks, script->main);
+  DEBUG ("<-- optimization done\n");
+  return stmt;
 }
 
diff --git a/vivified/code/vivi_decompiler.h b/vivified/code/vivi_decompiler.h
index ccb99fd..943a040 100644
--- a/vivified/code/vivi_decompiler.h
+++ b/vivified/code/vivi_decompiler.h
@@ -26,33 +26,8 @@
 G_BEGIN_DECLS
 
 
-typedef struct _ViviDecompiler ViviDecompiler;
-typedef struct _ViviDecompilerClass ViviDecompilerClass;
+ViviCodeStatement *	vivi_decompile_script		(SwfdecScript *		script);
 
-#define VIVI_TYPE_DECOMPILER                    (vivi_decompiler_get_type())
-#define VIVI_IS_DECOMPILER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER))
-#define VIVI_IS_DECOMPILER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER))
-#define VIVI_DECOMPILER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER, ViviDecompiler))
-#define VIVI_DECOMPILER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
-#define VIVI_DECOMPILER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
-
-struct _ViviDecompiler
-{
-  SwfdecAsObject	object;
-
-  SwfdecScript *	script;		/* script that we decompile */
-  GList *		blocks;		/* list of all blocks in this script ordered by pc (should be one after decompilation is done) */
-};
-
-struct _ViviDecompilerClass
-{
-  SwfdecAsObjectClass	object_class;
-};
-
-GType			vivi_decompiler_get_type   	(void);
-
-ViviDecompiler *	vivi_decompiler_new		(SwfdecScript *		script);
-ViviCodeBlock *		vivi_decompiler_get_block	(ViviDecompiler *	dec);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index e1f455b..14cec1c 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -197,6 +197,25 @@ vivi_decompiler_block_get_branch_condition (ViviDecompilerBlock *block)
 
 void
 vivi_decompiler_block_add_error (ViviDecompilerBlock *block,
+    ViviDecompilerState *state, const char *format, ...)
+{
+  ViviCodeToken *token;
+  va_list varargs;
+  char *s;
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+
+  token = vivi_code_comment_new (s);
+  g_printerr ("ERROR: %s\n", s);
+  g_free (s);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (token));
+  vivi_decompiler_block_finish (block, state);
+}
+
+void
+vivi_decompiler_block_add_warning (ViviDecompilerBlock *block,
     const char *format, ...)
 {
   ViviCodeToken *token;
@@ -208,6 +227,7 @@ vivi_decompiler_block_add_error (ViviDecompilerBlock *block,
   va_end (varargs);
 
   token = vivi_code_comment_new (s);
+  g_printerr ("WARNING: %s\n", s);
   g_free (s);
   vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (token));
 }
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
index 3881982..5defb39 100644
--- a/vivified/code/vivi_decompiler_block.h
+++ b/vivified/code/vivi_decompiler_block.h
@@ -87,6 +87,10 @@ ViviDecompilerBlock *	vivi_decompiler_block_get_branch	(ViviDecompilerBlock *		b
 ViviCodeValue *		vivi_decompiler_block_get_branch_condition
 								(ViviDecompilerBlock *		block);
 void			vivi_decompiler_block_add_error		(ViviDecompilerBlock *		block,
+								 ViviDecompilerState *		state,
+								 const char *			format,
+								 ...) G_GNUC_PRINTF (3, 4);
+void			vivi_decompiler_block_add_warning	(ViviDecompilerBlock *		block,
 								 const char *			format,
 								 ...) G_GNUC_PRINTF (2, 3);
 
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index a0139fa..a6d93d5 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -142,6 +142,12 @@ vivi_decompiler_state_add_pc (ViviDecompilerState *state, int diff)
   state->pc += diff;
 }
 
+SwfdecScript *
+vivi_decompiler_state_get_script (const ViviDecompilerState *state)
+{
+  return state->script;
+}
+
 const SwfdecConstantPool *
 vivi_decompiler_state_get_constant_pool (const ViviDecompilerState *state)
 {
diff --git a/vivified/code/vivi_decompiler_state.h b/vivified/code/vivi_decompiler_state.h
index eda42fd..041b624 100644
--- a/vivified/code/vivi_decompiler_state.h
+++ b/vivified/code/vivi_decompiler_state.h
@@ -49,6 +49,7 @@ ViviCodeValue *			vivi_decompiler_state_get_register (const ViviDecompilerState
 const guint8 *			vivi_decompiler_state_get_pc	(const ViviDecompilerState *	state);
 void				vivi_decompiler_state_add_pc	(ViviDecompilerState *		state,
 								 int				diff);
+SwfdecScript *	        	vivi_decompiler_state_get_script(const ViviDecompilerState *	state);
 const SwfdecConstantPool *    	vivi_decompiler_state_get_constant_pool 
 								(const ViviDecompilerState *	state);
 void				vivi_decompiler_state_set_constant_pool 
commit 030fa20a4d57f392106019bd0b91e393bcf064fd
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Mar 24 13:09:20 2008 +0100

    decompile function calls

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index d3a1644..3fda037 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -13,6 +13,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_comment.c \
 	vivi_code_constant.c \
 	vivi_code_continue.c \
+	vivi_code_function_call.c \
 	vivi_code_get.c \
 	vivi_code_get_url.c \
 	vivi_code_goto.c \
@@ -42,6 +43,7 @@ noinst_HEADERS = \
 	vivi_code_comment.h \
 	vivi_code_constant.h \
 	vivi_code_continue.h \
+	vivi_code_function_call.h \
 	vivi_code_get.h \
 	vivi_code_get_url.h \
 	vivi_code_goto.h \
diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
index e12c896..51c680f 100644
--- a/vivified/code/vivi_code_constant.c
+++ b/vivified/code/vivi_code_constant.c
@@ -22,6 +22,7 @@
 #endif
 
 #include <ctype.h>
+#include <math.h>
 #include <string.h>
 
 #include "vivi_code_constant.h"
@@ -214,3 +215,23 @@ vivi_code_constant_get_variable_name (ViviCodeConstant *constant)
       g_assert_not_reached ();
   }
 }
+
+SwfdecAsValueType
+vivi_code_constant_get_value_type (ViviCodeConstant *constant)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_CONSTANT (constant), SWFDEC_AS_TYPE_UNDEFINED);
+
+  return constant->value.type;
+}
+
+double
+vivi_code_constant_get_number (ViviCodeConstant *constant)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_CONSTANT (constant), NAN);
+
+  if (SWFDEC_AS_VALUE_IS_NUMBER (&constant->value))
+    return SWFDEC_AS_VALUE_GET_NUMBER (&constant->value);
+  else
+    return NAN;
+}
+
diff --git a/vivified/code/vivi_code_constant.h b/vivified/code/vivi_code_constant.h
index e62e62f..714bcc2 100644
--- a/vivified/code/vivi_code_constant.h
+++ b/vivified/code/vivi_code_constant.h
@@ -58,6 +58,9 @@ ViviCodeValue *		vivi_code_constant_new_boolean	(gboolean		boolean);
 
 char *			vivi_code_constant_get_variable_name
 							(ViviCodeConstant *	constant);
+SwfdecAsValueType	vivi_code_constant_get_value_type
+							(ViviCodeConstant *	constant);
+double			vivi_code_constant_get_number	(ViviCodeConstant *	constant);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_function_call.c b/vivified/code/vivi_code_function_call.c
new file mode 100644
index 0000000..a16a9e2
--- /dev/null
+++ b/vivified/code/vivi_code_function_call.c
@@ -0,0 +1,177 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_function_call.h"
+#include "vivi_code_constant.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeFunctionCall, vivi_code_function_call, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_function_call_dispose (GObject *object)
+{
+  ViviCodeFunctionCall *call = VIVI_CODE_FUNCTION_CALL (object);
+
+  if (call->value)
+    g_object_unref (call->value);
+  if (call->name)
+    g_object_unref (call->name);
+  g_ptr_array_foreach (call->arguments, (GFunc) g_object_unref, NULL);
+  g_ptr_array_free (call->arguments, TRUE);
+
+  G_OBJECT_CLASS (vivi_code_function_call_parent_class)->dispose (object);
+}
+
+static ViviCodeValue * 
+vivi_code_function_call_optimize (ViviCodeValue *value, SwfdecAsValueType hint)
+{
+  ViviCodeFunctionCall *call = VIVI_CODE_FUNCTION_CALL (value);
+  ViviCodeValue *opt, *name;
+  guint i;
+
+  if (call->value)
+    value = vivi_code_value_optimize (call->value, SWFDEC_AS_TYPE_UNDEFINED);
+  else
+    value = NULL;
+  if (call->name)
+    name = vivi_code_value_optimize (call->name, SWFDEC_AS_TYPE_UNDEFINED);
+  else
+    name = NULL;
+
+  opt = vivi_code_function_call_new (value, name);
+  if (value)
+    g_object_unref (value);
+  if (name)
+    g_object_unref (name);
+  for (i = 0; i < call->arguments->len; i++) {
+    value = vivi_code_value_optimize (g_ptr_array_index (call->arguments, i),
+	SWFDEC_AS_TYPE_UNDEFINED);
+    vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (opt), value);
+    g_object_unref (value);
+  }
+  return opt;
+}
+
+static void
+vivi_code_function_call_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviCodeFunctionCall *call = VIVI_CODE_FUNCTION_CALL (token);
+  char *varname;
+  guint i;
+
+  if (call->name) {
+    if (VIVI_IS_CODE_CONSTANT (call->name))
+      varname = vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (call->name));
+    else
+      varname = NULL;
+
+    if (call->value) {
+      vivi_code_printer_print_value (printer, call->value, VIVI_PRECEDENCE_MEMBER);
+      if (varname) {
+	vivi_code_printer_print (printer, ".");
+	vivi_code_printer_print (printer, varname);
+      } else {
+	vivi_code_printer_print (printer, "[");
+	vivi_code_printer_print_value (printer, call->name, VIVI_PRECEDENCE_MIN);
+	vivi_code_printer_print (printer, "]");
+      }
+    } else {
+      if (varname) {
+	vivi_code_printer_print (printer, varname);
+      } else {
+	vivi_code_printer_print (printer, "eval (");
+	vivi_code_printer_print_value (printer, call->name, VIVI_PRECEDENCE_MIN);
+	vivi_code_printer_print (printer, ")");
+      }
+    }
+    g_free (varname);
+  } else {
+    vivi_code_printer_print_value (printer, call->value, VIVI_PRECEDENCE_MEMBER);
+  }
+  vivi_code_printer_print (printer, " (");
+  for (i = 0; i < call->arguments->len; i++) {
+    if (i > 0)
+      vivi_code_printer_print (printer, ", ");
+    vivi_code_printer_print_value (printer, g_ptr_array_index (call->arguments, i), VIVI_PRECEDENCE_COMMA);
+  }
+  vivi_code_printer_print (printer, ")");
+}
+
+static gboolean
+vivi_code_function_call_is_constant (ViviCodeValue *value)
+{
+  return FALSE;
+}
+
+static void
+vivi_code_function_call_class_init (ViviCodeFunctionCallClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_function_call_dispose;
+
+  token_class->print = vivi_code_function_call_print;
+
+  value_class->is_constant = vivi_code_function_call_is_constant;
+  value_class->optimize = vivi_code_function_call_optimize;
+}
+
+static void
+vivi_code_function_call_init (ViviCodeFunctionCall *call)
+{
+  ViviCodeValue *value = VIVI_CODE_VALUE (call);
+
+  vivi_code_value_set_precedence (value, VIVI_PRECEDENCE_CALL);
+
+  call->arguments = g_ptr_array_new ();
+}
+
+ViviCodeValue *
+vivi_code_function_call_new (ViviCodeValue *value, ViviCodeValue *name)
+{
+  ViviCodeFunctionCall *call;
+
+  g_return_val_if_fail (value != NULL || name != NULL, NULL);
+  g_return_val_if_fail (value == NULL || VIVI_IS_CODE_VALUE (value), NULL);
+  g_return_val_if_fail (name == NULL || VIVI_IS_CODE_VALUE (name), NULL);
+
+  call = g_object_new (VIVI_TYPE_CODE_FUNCTION_CALL, NULL);
+  if (value)
+    call->value = g_object_ref (value);
+  if (name)
+    call->name = g_object_ref (name);
+
+  return VIVI_CODE_VALUE (call);
+}
+
+void
+vivi_code_function_call_add_argument (ViviCodeFunctionCall *call, ViviCodeValue *argument)
+{
+  g_return_if_fail (VIVI_IS_CODE_FUNCTION_CALL (call));
+  g_return_if_fail (VIVI_IS_CODE_VALUE (argument));
+
+  g_ptr_array_add (call->arguments, g_object_ref (argument));
+}
+
diff --git a/vivified/code/vivi_code_function_call.h b/vivified/code/vivi_code_function_call.h
new file mode 100644
index 0000000..cd3ce32
--- /dev/null
+++ b/vivified/code/vivi_code_function_call.h
@@ -0,0 +1,61 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_FUNCTION_CALL_H_
+#define _VIVI_CODE_FUNCTION_CALL_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeFunctionCall ViviCodeFunctionCall;
+typedef struct _ViviCodeFunctionCallClass ViviCodeFunctionCallClass;
+
+#define VIVI_TYPE_CODE_FUNCTION_CALL                    (vivi_code_function_call_get_type())
+#define VIVI_IS_CODE_FUNCTION_CALL(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_FUNCTION_CALL))
+#define VIVI_IS_CODE_FUNCTION_CALL_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_FUNCTION_CALL))
+#define VIVI_CODE_FUNCTION_CALL(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_FUNCTION_CALL, ViviCodeFunctionCall))
+#define VIVI_CODE_FUNCTION_CALL_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_FUNCTION_CALL, ViviCodeFunctionCallClass))
+#define VIVI_CODE_FUNCTION_CALL_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_FUNCTION_CALL, ViviCodeFunctionCallClass))
+
+struct _ViviCodeFunctionCall
+{
+  ViviCodeValue		parent;
+
+  ViviCodeValue *	value;
+  ViviCodeValue *	name;
+  GPtrArray *		arguments;
+};
+
+struct _ViviCodeFunctionCallClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_function_call_get_type   	(void);
+
+ViviCodeValue *		vivi_code_function_call_new		(ViviCodeValue *	value,
+								 ViviCodeValue *	name);
+
+void			vivi_code_function_call_add_argument	(ViviCodeFunctionCall *	call,
+								 ViviCodeValue *	argument);
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 9382b60..f6c2d03 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -34,6 +34,7 @@
 #include "vivi_code_break.h"
 #include "vivi_code_constant.h"
 #include "vivi_code_continue.h"
+#include "vivi_code_function_call.h"
 #include "vivi_code_get.h"
 #include "vivi_code_get_url.h"
 #include "vivi_code_goto.h"
@@ -369,6 +370,65 @@ vivi_decompile_duplicate (ViviDecompilerBlock *block, ViviDecompilerState *state
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_function_call (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    ViviCodeValue *value, ViviCodeValue *name, ViviCodeValue *args)
+{
+  ViviCodeValue *call;
+  double d;
+  guint i, count;
+
+  call = vivi_code_function_call_new (value, name);
+  if (value)
+    g_object_unref (value);
+  if (name)
+    g_object_unref (name);
+
+  if (!VIVI_IS_CODE_CONSTANT (args) || 
+      vivi_code_constant_get_value_type (VIVI_CODE_CONSTANT (args)) != SWFDEC_AS_TYPE_NUMBER ||
+      ((count = d = vivi_code_constant_get_number (VIVI_CODE_CONSTANT (args))) != d)) {
+    vivi_decompiler_block_add_error (block, "could not determine function argument count");
+    g_object_unref (args);
+    g_object_unref (call);
+    return FALSE;
+  }
+  g_object_unref (args);
+
+  count = MIN (count, vivi_decompiler_state_get_stack_depth (state));
+  for (i = 0; i < count; i++) {
+    value = vivi_decompiler_state_pop (state);
+    vivi_code_function_call_add_argument (VIVI_CODE_FUNCTION_CALL (call), value);
+    g_object_unref (value);
+  }
+  vivi_decompiler_state_push (state, call);
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_call_function (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *name, *args;
+
+  name = vivi_decompiler_state_pop (state);
+  args = vivi_decompiler_state_pop (state);
+
+  return vivi_decompile_function_call (block, state, NULL, name, args);
+}
+
+static gboolean
+vivi_decompile_call_method (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *value, *name, *args;
+
+  name = vivi_decompiler_state_pop (state);
+  value = vivi_decompiler_state_pop (state);
+  args = vivi_decompiler_state_pop (state);
+
+  return vivi_decompile_function_call (block, state, value, name, args);
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
@@ -386,12 +446,14 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_OR] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_STRING_EQUALS] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_STRING_LESS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_CALL_FUNCTION] = vivi_decompile_call_function,
   [SWFDEC_AS_ACTION_ADD2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_LESS2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_EQUALS2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_PUSH_DUPLICATE] = vivi_decompile_duplicate,
   [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
   [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
+  [SWFDEC_AS_ACTION_CALL_METHOD] = vivi_decompile_call_method,
   [SWFDEC_AS_ACTION_BIT_AND] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_BIT_OR] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_BIT_XOR] = vivi_decompile_binary,
commit cd43fb6523efb875ad02c10510e3d31dd961883f
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 23:54:03 2008 +0100

    add testcase for handling of && and ||

diff --git a/vivified/code/test/Makefile.am b/vivified/code/test/Makefile.am
index 0bcdc91..b8c3087 100644
--- a/vivified/code/test/Makefile.am
+++ b/vivified/code/test/Makefile.am
@@ -14,9 +14,12 @@ check-local: ../vivi-decompile
 	fi
 
 EXTRA_DIST = \
+	and-or.as \
+	and-or.swf \
+	and-or.swf.expect \
 	hello-world.as \
 	hello-world.swf \
-	hello-world.swf.trace \
+	hello-world.swf.expect \
 	if.as \
 	if.swf \
 	if.swf.expect \
diff --git a/vivified/code/test/and-or.as b/vivified/code/test/and-or.as
new file mode 100644
index 0000000..0cbecce
--- /dev/null
+++ b/vivified/code/test/and-or.as
@@ -0,0 +1,16 @@
+// makeswf -v 7 -s 200x150 -r 1 -o and-or.swf and-or.as
+
+if (1 && 2)
+  trace (3);
+if (1 || 2)
+  trace (3);
+
+if (1 && 2 && 3)
+  trace (4);
+if (1 || 2 || 3)
+  trace (4);
+
+if ((1 && 2) || 3)
+  trace (4);
+if ((1 || 2) && 3)
+  trace (4);
diff --git a/vivified/code/test/and-or.swf b/vivified/code/test/and-or.swf
new file mode 100644
index 0000000..a7802e6
Binary files /dev/null and b/vivified/code/test/and-or.swf differ
diff --git a/vivified/code/test/and-or.swf.expect b/vivified/code/test/and-or.swf.expect
new file mode 100644
index 0000000..62706cd
--- /dev/null
+++ b/vivified/code/test/and-or.swf.expect
@@ -0,0 +1,18 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  if (1 && 2)
+    trace (3);
+  if (1 || 2)
+    trace (3);
+  if (1 && 2 && 3)
+    trace (4);
+  if (1 || 2 || 3)
+    trace (4);
+  if (1 && 2 || 3)
+    trace (4);
+  if ((1 || 2) && 3)
+    trace (4);
+}
+
commit 58e45c47032755b41c29101d5499d1d56e35ceff
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 23:52:01 2008 +0100

    various debugging improvements

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 6eb84f9..9382b60 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -63,7 +63,8 @@ DUMP_BLOCKS (ViviDecompiler *dec)
   g_print ("dumping blocks:\n");
   for (walk = dec->blocks; walk; walk = walk->next) {
     ViviDecompilerBlock *block = walk->data;
-    g_print ("  %p -> %p\n", vivi_decompiler_block_get_start (block), block->endpc);
+    g_printerr ("  %p -> %p\n", vivi_decompiler_block_get_start (block), 
+	block->end ? vivi_decompiler_state_get_pc (block->end) : NULL);
   }
 }
 #else
@@ -77,8 +78,9 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
   GList *walk;
   const guint8 *pc, *block_start;
 
-  DUMP_BLOCKS (dec);
   pc = vivi_decompiler_state_get_pc (state);
+  DEBUG ("pc: %p\n", pc);
+  DUMP_BLOCKS (dec);
   for (walk = dec->blocks; walk; walk = walk->next) {
     block = walk->data;
     block_start = vivi_decompiler_block_get_start (block);
@@ -1069,6 +1071,7 @@ vivi_decompiler_merge_blocks (GList *blocks, const guint8 *startpc)
 
   do {
     restart = FALSE;
+    DEBUG ("merging: %u blocks left\n", g_list_length (blocks));
 
     restart |= vivi_decompiler_merge_lines (&blocks);
     if (vivi_decompiler_merge_andor (&blocks)) {
commit 9c4991f1b38704e142d0b9b06746741b34b54e1d
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 23:50:48 2008 +0100

    make extra sure we contain the desired block
    
    gets around nasty code jumping into scripts

diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index b330927..e1f455b 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -221,13 +221,28 @@ vivi_decompiler_block_get_start (ViviDecompilerBlock *block)
 gboolean
 vivi_decompiler_block_contains (ViviDecompilerBlock *block, const guint8 *pc)
 {
+  const guint8 *check;
+  guint code;
+
   g_return_val_if_fail (VIVI_IS_DECOMPILER_BLOCK (block), FALSE);
   g_return_val_if_fail (pc != NULL, FALSE);
 
+  if (pc == block->startpc)
+    return TRUE;
   if (block->end == NULL)
     return FALSE;
 
-  return pc >= block->startpc && pc < vivi_decompiler_state_get_pc (block->end);
+  if (pc >= vivi_decompiler_state_get_pc (block->end))
+    return FALSE;
+  for (check = block->startpc; check < pc; ) {
+    code = *check;
+    if (code & 0x80) {
+      check += (check[1] | check[2] << 8) + 3;
+    } else {
+      check++;
+    }
+  }
+  return check == pc;
 }
 
 void
commit 8e0b04b3ee98132fdccd3008a757fbe16ca25c8b
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 23:16:26 2008 +0100

    make the code less crashy

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index b3c267c..6eb84f9 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -815,12 +815,12 @@ vivi_decompiler_merge_if (GList **list)
       vivi_decompiler_block_set_next (if_block, NULL);
       vivi_decompiler_block_set_branch (if_block, NULL, NULL);
       vivi_decompiler_block_add_to_block (if_block, b);
-      vivi_decompiler_block_add_state_transition (if_block, 
-	  vivi_decompiler_block_get_next (block), b);
+      if (next)
+	vivi_decompiler_block_add_state_transition (if_block, next, b);
       *list = vivi_decompiler_purge_block (*list, if_block);
     } else {
-      vivi_decompiler_block_add_state_transition (block, 
-	  vivi_decompiler_block_get_next (block), b);
+      if (next)
+	vivi_decompiler_block_add_state_transition (block, next, b);
     }
     stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (b));
     g_object_unref (b);
@@ -834,12 +834,12 @@ vivi_decompiler_merge_if (GList **list)
       vivi_decompiler_block_set_next (else_block, NULL);
       vivi_decompiler_block_set_branch (else_block, NULL, NULL);
       vivi_decompiler_block_add_to_block (else_block, b);
-      vivi_decompiler_block_add_state_transition (else_block, 
-	  vivi_decompiler_block_get_next (block), b);
+      if (next)
+	vivi_decompiler_block_add_state_transition (else_block, next, b);
       *list = vivi_decompiler_purge_block (*list, else_block);
     } else {
-      vivi_decompiler_block_add_state_transition (block, 
-	  vivi_decompiler_block_get_next (block), b);
+      if (next)
+	vivi_decompiler_block_add_state_transition (block, next, b);
     }
     stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (b));
     g_object_unref (b);
@@ -854,7 +854,8 @@ vivi_decompiler_merge_if (GList **list)
       vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
       g_object_unref (stmt);
     }
-    vivi_decompiler_block_finish (block, vivi_decompiler_block_get_start_state (next));
+    if (next)
+      vivi_decompiler_block_finish (block, vivi_decompiler_block_get_start_state (next));
     result = TRUE;
   }
 
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index d2228f2..b330927 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -275,6 +275,10 @@ vivi_decompiler_block_add_state_transition (ViviDecompilerBlock *from,
   guint i, len;
   
   len = vivi_decompiler_state_get_stack_depth (to->start);
+  if (from->end == NULL) {
+    g_printerr ("broken source - no state transition possible\n");
+    return;
+  }
 
   for (i = 0; i < len; i++) {
     ViviCodeValue *name;
@@ -286,6 +290,10 @@ vivi_decompiler_block_add_state_transition (ViviDecompilerBlock *from,
       continue;
 
     val_from = vivi_decompiler_state_peek_nth (from->end, i);
+    if (val_from == NULL) {
+      g_printerr ("incompatible states - aborting transition\n");
+      return;
+    }
     if (val_from != VIVI_CODE_VALUE (val_to)) {
       name = vivi_code_constant_new_string (vivi_decompiler_unknown_get_name (val_to));
       vivi_code_block_add_statement (block,
commit 4423b441bb543badaa458aba517c960fa37fdcae
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 23:07:41 2008 +0100

    disable debugging

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 371178a..b3c267c 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -48,7 +48,7 @@
 #include "vivi_decompiler_state.h"
 #include "vivi_decompiler_unknown.h"
 
-#if 1
+#if 0
 #define DEBUG g_printerr
 #else
 #define DEBUG(...)
@@ -751,10 +751,8 @@ vivi_decompiler_merge_andor (GList **list)
     /* possibly update the start state of the next block */
     if (vivi_decompiler_block_get_n_incoming (next) == 1) {
       value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_start_state (next), 0);
-      DEBUG ("resolving unknown (1)\n");
       if (VIVI_IS_DECOMPILER_UNKNOWN (value2) &&
 	  vivi_decompiler_unknown_get_block (VIVI_DECOMPILER_UNKNOWN (value2)) == next) {
-	DEBUG ("resolving unknown (2)\n");
 	vivi_decompiler_unknown_set_value (VIVI_DECOMPILER_UNKNOWN (value2), value);
       }
     }
commit 5eb5a7f5dcda727ca1ffff9ac10966f87cbd55fc
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 23:06:43 2008 +0100

    make decompiler unknowns depend on the block they're defined in

diff --git a/vivified/code/vivi_code_value.c b/vivified/code/vivi_code_value.c
index e5339c7..722eb66 100644
--- a/vivified/code/vivi_code_value.c
+++ b/vivified/code/vivi_code_value.c
@@ -92,3 +92,12 @@ vivi_code_value_optimize (ViviCodeValue *value, SwfdecAsValueType hint)
   }
 }
 
+gboolean
+vivi_code_value_is_equal (ViviCodeValue *a, ViviCodeValue *b)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (a), FALSE);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (b), FALSE);
+
+  return a == b;
+}
+
diff --git a/vivified/code/vivi_code_value.h b/vivified/code/vivi_code_value.h
index 924b310..ae66a9c 100644
--- a/vivified/code/vivi_code_value.h
+++ b/vivified/code/vivi_code_value.h
@@ -78,6 +78,8 @@ struct _ViviCodeValueClass
 GType			vivi_code_value_get_type   	(void);
 
 gboolean		vivi_code_value_is_constant	(ViviCodeValue *	value);
+gboolean		vivi_code_value_is_equal	(ViviCodeValue *	a,
+							 ViviCodeValue *	b);
 
 void			vivi_code_value_set_precedence	(ViviCodeValue *	value,
 							 ViviPrecedence		precedence);
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index e21f1f2..371178a 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -48,6 +48,12 @@
 #include "vivi_decompiler_state.h"
 #include "vivi_decompiler_unknown.h"
 
+#if 1
+#define DEBUG g_printerr
+#else
+#define DEBUG(...)
+#endif
+
 #if 0
 static G_GNUC_UNUSED void
 DUMP_BLOCKS (ViviDecompiler *dec)
@@ -92,7 +98,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 	vivi_decompiler_state_free (state);
 	return block;
       }
-      if (!vivi_decompiler_state_is_equal (block_state, state))
+      if (!vivi_decompiler_block_is_compatible (block, state))
 	vivi_decompiler_block_reset (block, TRUE);
       vivi_decompiler_state_free (state);
       return block;
@@ -731,6 +737,7 @@ vivi_decompiler_merge_andor (GList **list)
       continue;
 
     /* setting code starts here */
+    DEBUG ("merging %s code for %p\n", type, vivi_decompiler_block_get_start (andor));
 
     /* update our finish state */
     value = vivi_code_binary_new_name (value, value2, type);
@@ -744,8 +751,12 @@ vivi_decompiler_merge_andor (GList **list)
     /* possibly update the start state of the next block */
     if (vivi_decompiler_block_get_n_incoming (next) == 1) {
       value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_start_state (next), 0);
-      if (VIVI_IS_DECOMPILER_UNKNOWN (value2))
+      DEBUG ("resolving unknown (1)\n");
+      if (VIVI_IS_DECOMPILER_UNKNOWN (value2) &&
+	  vivi_decompiler_unknown_get_block (VIVI_DECOMPILER_UNKNOWN (value2)) == next) {
+	DEBUG ("resolving unknown (2)\n");
 	vivi_decompiler_unknown_set_value (VIVI_DECOMPILER_UNKNOWN (value2), value);
+      }
     }
     return TRUE;
   }
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index debd718..d2228f2 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -95,7 +95,7 @@ vivi_decompiler_block_reset (ViviDecompilerBlock *block, gboolean generalize_sta
     for (i = 0; i < len; i++) {
       char *s = g_strdup_printf ("$stack%u", len - i);
       vivi_decompiler_state_push (block->start,
-	  vivi_decompiler_unknown_new (s));
+	  vivi_decompiler_unknown_new (block, s));
       g_free (s);
     }
   }
@@ -336,3 +336,24 @@ vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
   }
 }
 
+gboolean
+vivi_decompiler_block_is_compatible (ViviDecompilerBlock *block, const ViviDecompilerState *state)
+{
+  guint i, n;
+
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_BLOCK (block), FALSE);
+  g_return_val_if_fail (state != NULL, FALSE);
+
+  n = vivi_decompiler_state_get_stack_depth (state);
+  for (i = 0; i < n; i++) {
+    ViviCodeValue *val = vivi_decompiler_state_peek_nth (block->start, i);
+
+    if (VIVI_IS_DECOMPILER_UNKNOWN (val) &&
+	vivi_decompiler_unknown_get_block (VIVI_DECOMPILER_UNKNOWN (val)) == block)
+      continue;
+    if (!vivi_code_value_is_equal (vivi_decompiler_state_peek_nth (state, i), val))
+      return FALSE;
+  }
+  return TRUE;
+}
+
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
index 35e7d6b..3881982 100644
--- a/vivified/code/vivi_decompiler_block.h
+++ b/vivified/code/vivi_decompiler_block.h
@@ -73,6 +73,8 @@ gboolean		vivi_decompiler_block_contains		(ViviDecompilerBlock *  	block,
 void			vivi_decompiler_block_finish		(ViviDecompilerBlock *		block,
 								 const ViviDecompilerState *	state);
 gboolean		vivi_decompiler_block_is_finished	(ViviDecompilerBlock *		block);
+gboolean		vivi_decompiler_block_is_compatible	(ViviDecompilerBlock *		block,
+								 const ViviDecompilerState *	state);
 
 guint			vivi_decompiler_block_get_n_incoming	(ViviDecompilerBlock *		block);
 void			vivi_decompiler_block_set_next		(ViviDecompilerBlock *		block,
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index d30e33e..a0139fa 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -193,31 +193,3 @@ vivi_decompiler_state_is_compatible (const ViviDecompilerState *a, const ViviDec
   return TRUE;
 }
 
-gboolean
-vivi_decompiler_state_is_equal (const ViviDecompilerState *a, const ViviDecompilerState *b)
-{
-  ViviCodeValue *vala, *valb;
-  GSList *walka, *walkb;
-
-  g_return_val_if_fail (a != NULL, FALSE);
-  g_return_val_if_fail (b != NULL, FALSE);
-
-  if (!vivi_decompiler_state_is_compatible (a, b))
-    return FALSE;
-
-  for (walka = a->stack, walkb = b->stack; walka && walkb; walka = walka->next, walkb = walkb->next) {
-    vala = walka->data;
-    valb = walkb->data;
-    
-    if (VIVI_IS_DECOMPILER_UNKNOWN (vala) &&
-	vivi_decompiler_unknown_get_value (VIVI_DECOMPILER_UNKNOWN (vala)) == NULL)
-      continue;
-    if (VIVI_IS_DECOMPILER_UNKNOWN (valb) &&
-	vivi_decompiler_unknown_get_value (VIVI_DECOMPILER_UNKNOWN (valb)) == NULL)
-      continue;
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
diff --git a/vivified/code/vivi_decompiler_state.h b/vivified/code/vivi_decompiler_state.h
index 990fc81..eda42fd 100644
--- a/vivified/code/vivi_decompiler_state.h
+++ b/vivified/code/vivi_decompiler_state.h
@@ -21,6 +21,7 @@
 #define _VIVI_DECOMPILER_STATE_H_
 
 #include <swfdec/swfdec.h>
+#include <swfdec/swfdec_script_internal.h>
 #include <vivified/code/vivi_code_value.h>
 
 G_BEGIN_DECLS
@@ -59,8 +60,6 @@ guint				vivi_decompiler_state_get_version
 gboolean			vivi_decompiler_state_is_compatible	
 								(const ViviDecompilerState *	a,
 								 const ViviDecompilerState *	b);
-gboolean			vivi_decompiler_state_is_equal	(const ViviDecompilerState *	a,
-								 const ViviDecompilerState *	b);
 
 
 
diff --git a/vivified/code/vivi_decompiler_unknown.c b/vivified/code/vivi_decompiler_unknown.c
index de5e4c5..4545069 100644
--- a/vivified/code/vivi_decompiler_unknown.c
+++ b/vivified/code/vivi_decompiler_unknown.c
@@ -95,14 +95,17 @@ vivi_decompiler_unknown_init (ViviDecompilerUnknown *unknown)
 }
 
 ViviCodeValue *
-vivi_decompiler_unknown_new (const char *name)
+vivi_decompiler_unknown_new (ViviDecompilerBlock *block, const char *name)
 {
   ViviDecompilerUnknown *unknown;
 
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_BLOCK (block), NULL);
   g_return_val_if_fail (name != NULL, NULL);
 
   unknown = g_object_new (VIVI_TYPE_DECOMPILER_UNKNOWN, NULL);
   unknown->name = g_strdup (name);
+  /* NB: can't ref the block due to cycles */
+  unknown->block = block;
 
   return VIVI_CODE_VALUE (unknown);
 }
@@ -138,3 +141,11 @@ vivi_decompiler_unknown_get_name (ViviDecompilerUnknown *unknown)
   return unknown->name;
 }
 
+ViviDecompilerBlock *
+vivi_decompiler_unknown_get_block (ViviDecompilerUnknown *unknown)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_UNKNOWN (unknown), NULL);
+
+  return unknown->block;
+}
+
diff --git a/vivified/code/vivi_decompiler_unknown.h b/vivified/code/vivi_decompiler_unknown.h
index d5ca3b6..ac0cd7e 100644
--- a/vivified/code/vivi_decompiler_unknown.h
+++ b/vivified/code/vivi_decompiler_unknown.h
@@ -21,6 +21,7 @@
 #define _VIVI_DECOMPILER_UNKNOWN_H_
 
 #include <vivified/code/vivi_code_value.h>
+#include <vivified/code/vivi_decompiler_block.h>
 
 G_BEGIN_DECLS
 
@@ -41,6 +42,7 @@ struct _ViviDecompilerUnknown
 
   char *		name;
   ViviCodeValue *	value;
+  ViviDecompilerBlock *	block;
 };
 
 struct _ViviDecompilerUnknownClass
@@ -50,12 +52,14 @@ struct _ViviDecompilerUnknownClass
 
 GType			vivi_decompiler_unknown_get_type   	(void);
 
-ViviCodeValue *		vivi_decompiler_unknown_new		(const char *		name);
+ViviCodeValue *		vivi_decompiler_unknown_new		(ViviDecompilerBlock *	block,
+								 const char *		name);
 
 void			vivi_decompiler_unknown_set_value	(ViviDecompilerUnknown *unknown,
 								 ViviCodeValue *	value);
 ViviCodeValue *		vivi_decompiler_unknown_get_value	(ViviDecompilerUnknown *unknown);
 const char *		vivi_decompiler_unknown_get_name	(ViviDecompilerUnknown *unknown);
+ViviDecompilerBlock *	vivi_decompiler_unknown_get_block	(ViviDecompilerUnknown *unknown);
 
 
 G_END_DECLS
commit 7a62326711f52ac61eee08e0619ce58a87217c88
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 20:06:32 2008 +0100

    implement || and && parsing

diff --git a/vivified/code/vivi_code_binary.c b/vivified/code/vivi_code_binary.c
index da71d38..1b69476 100644
--- a/vivified/code/vivi_code_binary.c
+++ b/vivified/code/vivi_code_binary.c
@@ -52,7 +52,9 @@ static struct {
   { ">>>",	SWFDEC_AS_ACTION_BIT_URSHIFT,	VIVI_PRECEDENCE_SHIFT },
   { "===",	SWFDEC_AS_ACTION_STRICT_EQUALS,	VIVI_PRECEDENCE_EQUALITY },
   { ">",	SWFDEC_AS_ACTION_GREATER,	VIVI_PRECEDENCE_RELATIONAL },
-  { "gt",	SWFDEC_AS_ACTION_STRING_GREATER,VIVI_PRECEDENCE_RELATIONAL }
+  { "gt",	SWFDEC_AS_ACTION_STRING_GREATER,VIVI_PRECEDENCE_RELATIONAL },
+  { "&&",	0,				VIVI_PRECEDENCE_AND },
+  { "||",	0,				VIVI_PRECEDENCE_OR }
 };
 
 G_DEFINE_TYPE (ViviCodeBinary, vivi_code_binary, VIVI_TYPE_CODE_VALUE)
@@ -135,3 +137,29 @@ vivi_code_binary_new_bytecode (ViviCodeValue *left, ViviCodeValue *right, guint
   return VIVI_CODE_VALUE (binary);
 }
 
+ViviCodeValue *
+vivi_code_binary_new_name (ViviCodeValue *left, ViviCodeValue *right, const char *name)
+{
+  ViviCodeBinary *binary;
+  guint id;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (left), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (right), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+  for (id = 0; id < G_N_ELEMENTS (operation_table); id++) {
+    if (g_str_equal (operation_table[id].operation, name))
+      break;
+  }
+  g_return_val_if_fail (id < G_N_ELEMENTS (operation_table), NULL);
+
+  binary = g_object_new (VIVI_TYPE_CODE_BINARY, NULL);
+  binary->left = g_object_ref (left);
+  binary->right = g_object_ref (right);
+  binary->operation_index = id;
+
+  vivi_code_value_set_precedence (VIVI_CODE_VALUE (binary), 
+      operation_table[id].precedence);
+
+  return VIVI_CODE_VALUE (binary);
+}
+
diff --git a/vivified/code/vivi_code_binary.h b/vivified/code/vivi_code_binary.h
index f3ea996..cd71f97 100644
--- a/vivified/code/vivi_code_binary.h
+++ b/vivified/code/vivi_code_binary.h
@@ -54,6 +54,9 @@ GType			vivi_code_binary_get_type   	(void);
 ViviCodeValue *		vivi_code_binary_new_bytecode 	(ViviCodeValue *	left,
 							 ViviCodeValue *	right,
 							 guint			code);
+ViviCodeValue *		vivi_code_binary_new_name	(ViviCodeValue *	left,
+							 ViviCodeValue *	right,
+							 const char *		name);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
index 858ac1f..9e50338 100644
--- a/vivified/code/vivi_code_unary.c
+++ b/vivified/code/vivi_code_unary.c
@@ -109,3 +109,11 @@ vivi_code_unary_new (ViviCodeValue *value, char operation)
   return VIVI_CODE_VALUE (unary);
 }
 
+ViviCodeValue *
+vivi_code_unary_get_value (ViviCodeUnary *unary)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_UNARY (unary), NULL);
+
+  return unary->value;
+}
+
diff --git a/vivified/code/vivi_code_unary.h b/vivified/code/vivi_code_unary.h
index 23f93c0..70eeeb8 100644
--- a/vivified/code/vivi_code_unary.h
+++ b/vivified/code/vivi_code_unary.h
@@ -53,7 +53,7 @@ GType			vivi_code_unary_get_type   	(void);
 ViviCodeValue *		vivi_code_unary_new		(ViviCodeValue *	value,
 							 char			operation);
 
-char			vivi_code_unary_get_operation	(ViviCodeUnary *	unary);
+ViviCodeValue *		vivi_code_unary_get_value	(ViviCodeUnary *	unary);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_value_statement.c b/vivified/code/vivi_code_value_statement.c
index 1b94c57..7677179 100644
--- a/vivified/code/vivi_code_value_statement.c
+++ b/vivified/code/vivi_code_value_statement.c
@@ -75,3 +75,11 @@ vivi_code_value_statement_new (ViviCodeValue *value)
   return VIVI_CODE_STATEMENT (stmt);
 }
 
+ViviCodeValue *
+vivi_code_value_statement_get_value (ViviCodeValueStatement *stmt)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE_STATEMENT (stmt), NULL);
+
+  return stmt->value;
+}
+
diff --git a/vivified/code/vivi_code_value_statement.h b/vivified/code/vivi_code_value_statement.h
index 8b0a087..27d42e3 100644
--- a/vivified/code/vivi_code_value_statement.h
+++ b/vivified/code/vivi_code_value_statement.h
@@ -52,5 +52,8 @@ GType			vivi_code_value_statement_get_type   	(void);
 
 ViviCodeStatement *   	vivi_code_value_statement_new		(ViviCodeValue *	value);
 
+ViviCodeValue *   	vivi_code_value_statement_get_value	(ViviCodeValueStatement *stmt);
+
+
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 1a2d4ca..e21f1f2 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -46,6 +46,7 @@
 #include "vivi_decompiler_block.h"
 #include "vivi_decompiler_duplicate.h"
 #include "vivi_decompiler_state.h"
+#include "vivi_decompiler_unknown.h"
 
 #if 0
 static G_GNUC_UNUSED void
@@ -356,7 +357,6 @@ vivi_decompile_duplicate (ViviDecompilerBlock *block, ViviDecompilerState *state
   value = vivi_decompiler_state_pop (state);
   vivi_decompiler_state_push (state, value);
   dupl = vivi_decompiler_duplicate_new (value);
-  g_object_unref (value);
   vivi_decompiler_state_push (state, dupl);
   return TRUE;
 }
@@ -662,7 +662,97 @@ vivi_decompiler_merge_lines (GList **list)
   return result;
 }
 
-/*     CONDi
+/*      DUP
+ *     (NOT)
+ *     BLOCK
+ *    /   |
+ *[ANDOR] |
+ *    \   |
+ *     NEXT
+ */
+static gboolean
+vivi_decompiler_merge_andor (GList **list)
+{
+  ViviDecompilerBlock *block, *andor, *next;
+  gboolean result;
+  const char *type;
+  ViviCodeValue *value, *value2;
+  ViviDecompilerState *state;
+
+  GList *walk;
+  result = FALSE;
+  for (walk = *list; walk; walk = walk->next) {
+    block = walk->data;
+
+    next = vivi_decompiler_block_get_branch (block);
+    andor = vivi_decompiler_block_get_next (block);
+
+    /* not an if block */
+    if (andor == NULL)
+      continue;
+
+    /* not an && or || block */
+    if (vivi_decompiler_block_get_n_incoming (andor) > 1 ||
+	next != vivi_decompiler_block_get_next (andor) ||
+	vivi_decompiler_block_get_branch (andor) != NULL)
+      continue;
+    /* extract the value */
+    value = vivi_decompiler_block_get_branch_condition (block);
+    if (VIVI_IS_CODE_UNARY (value)) {
+      value = vivi_code_unary_get_value (VIVI_CODE_UNARY (value));
+      type = "&&";
+    } else {
+      type = "||";
+    }
+    if (!VIVI_IS_DECOMPILER_DUPLICATE (value))
+      continue;
+    value = vivi_decompiler_duplicate_get_value (VIVI_DECOMPILER_DUPLICATE (value));
+    /* check the extracted value is the only statement in the and/or block */
+    switch (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (andor))) {
+      case 0:
+	break;
+      case 1:
+	{
+	  ViviCodeStatement *stmt = vivi_code_block_get_statement (VIVI_CODE_BLOCK (andor), 0);
+	  if (!VIVI_IS_CODE_VALUE_STATEMENT (stmt))
+	    continue;
+	  if (value != vivi_code_value_statement_get_value (VIVI_CODE_VALUE_STATEMENT (stmt)))
+	    continue;
+	}
+	break;
+      default:
+	continue;
+    }
+    value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_end_state (block), 0);
+    if (value != value2)
+      continue;
+    value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_end_state (andor), 0);
+    if (value2 == NULL)
+      continue;
+
+    /* setting code starts here */
+
+    /* update our finish state */
+    value = vivi_code_binary_new_name (value, value2, type);
+    state = (ViviDecompilerState *) vivi_decompiler_block_get_end_state (block);
+    g_object_unref (vivi_decompiler_state_pop (state));
+    vivi_decompiler_state_push (state, value);
+    /* get rid of the and/or block */
+    vivi_decompiler_block_set_branch (block, NULL, NULL);
+    vivi_decompiler_block_set_next (block, next);
+    *list = vivi_decompiler_purge_block (*list, andor);
+    /* possibly update the start state of the next block */
+    if (vivi_decompiler_block_get_n_incoming (next) == 1) {
+      value2 = vivi_decompiler_state_peek_nth (vivi_decompiler_block_get_start_state (next), 0);
+      if (VIVI_IS_DECOMPILER_UNKNOWN (value2))
+	vivi_decompiler_unknown_set_value (VIVI_DECOMPILER_UNKNOWN (value2), value);
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*     COND
  *    /    \
  *  [IF] [ELSE]     ==>   BLOCK
  *    \    /
@@ -971,6 +1061,10 @@ vivi_decompiler_merge_blocks (GList *blocks, const guint8 *startpc)
     restart = FALSE;
 
     restart |= vivi_decompiler_merge_lines (&blocks);
+    if (vivi_decompiler_merge_andor (&blocks)) {
+      restart = TRUE;
+      continue;
+    }
     restart |= vivi_decompiler_merge_if (&blocks);
     restart |= vivi_decompiler_merge_loops (&blocks);
   } while (restart);
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index 9cda41f..debd718 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -256,6 +256,12 @@ vivi_decompiler_block_get_start_state (ViviDecompilerBlock *block)
   return block->start;
 }
 
+const ViviDecompilerState *
+vivi_decompiler_block_get_end_state (ViviDecompilerBlock *block)
+{
+  return block->end;
+}
+
 guint
 vivi_decompiler_block_get_n_incoming (ViviDecompilerBlock *block)
 {
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
index 47a637b..35e7d6b 100644
--- a/vivified/code/vivi_decompiler_block.h
+++ b/vivified/code/vivi_decompiler_block.h
@@ -63,9 +63,11 @@ void			vivi_decompiler_block_reset		(ViviDecompilerBlock *		block,
 
 ViviCodeStatement *	vivi_decompiler_block_get_label		(ViviDecompilerBlock *  	block);
 void			vivi_decompiler_block_force_label	(ViviDecompilerBlock *		block);
+const guint8 *		vivi_decompiler_block_get_start		(ViviDecompilerBlock *		block);
 const ViviDecompilerState *
 			vivi_decompiler_block_get_start_state	(ViviDecompilerBlock *	        block);
-const guint8 *		vivi_decompiler_block_get_start		(ViviDecompilerBlock *		block);
+const ViviDecompilerState *
+			vivi_decompiler_block_get_end_state	(ViviDecompilerBlock *	        block);
 gboolean		vivi_decompiler_block_contains		(ViviDecompilerBlock *  	block,
 								 const guint8 *			pc);
 void			vivi_decompiler_block_finish		(ViviDecompilerBlock *		block,
diff --git a/vivified/code/vivi_decompiler_duplicate.c b/vivified/code/vivi_decompiler_duplicate.c
index c5ab825..f1fd71d 100644
--- a/vivified/code/vivi_decompiler_duplicate.c
+++ b/vivified/code/vivi_decompiler_duplicate.c
@@ -85,3 +85,11 @@ vivi_decompiler_duplicate_new (ViviCodeValue *value)
   return VIVI_CODE_VALUE (dupl);
 }
 
+ViviCodeValue *
+vivi_decompiler_duplicate_get_value (ViviDecompilerDuplicate *dupl)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_DUPLICATE (dupl), NULL);
+
+  return dupl->value;
+}
+
diff --git a/vivified/code/vivi_decompiler_duplicate.h b/vivified/code/vivi_decompiler_duplicate.h
index 5b48bb0..01265ed 100644
--- a/vivified/code/vivi_decompiler_duplicate.h
+++ b/vivified/code/vivi_decompiler_duplicate.h
@@ -51,6 +51,8 @@ GType			vivi_decompiler_duplicate_get_type   	(void);
 
 ViviCodeValue *		vivi_decompiler_duplicate_new		(ViviCodeValue *	value);
 
+ViviCodeValue *		vivi_decompiler_duplicate_get_value	(ViviDecompilerDuplicate *dupl);
+
 
 G_END_DECLS
 #endif
commit 1be3403d0581e7dc4e01e75fb8f067977a849b82
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 20:06:11 2008 +0100

    properly optimize

diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 2459e6c..07880dc 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -50,26 +50,29 @@ vivi_code_if_optimize (ViviCodeStatement *statement)
 
   if_stmt = stmt->if_statement ? vivi_code_statement_optimize (stmt->if_statement) : NULL;
   else_stmt = stmt->else_statement ? vivi_code_statement_optimize (stmt->else_statement) : NULL;
-#if 0
   if (if_stmt == NULL && else_stmt == NULL)
     return NULL;
-#endif
 
-  cond = g_object_ref (stmt->condition);
   if (if_stmt == NULL && else_stmt != NULL) {
-    cond = VIVI_CODE_VALUE (vivi_code_unary_new (cond, '!'));
+    tmp = VIVI_CODE_VALUE (vivi_code_unary_new (stmt->condition, '!'));
+    cond = vivi_code_value_optimize (tmp, SWFDEC_AS_TYPE_BOOLEAN);
+    g_object_unref (tmp);
     if_stmt = else_stmt;
     else_stmt = NULL;
+  } else {
+    cond = vivi_code_value_optimize (stmt->condition, SWFDEC_AS_TYPE_BOOLEAN);
   }
-  tmp = vivi_code_value_optimize (cond, SWFDEC_AS_TYPE_BOOLEAN);
-  g_object_unref (cond);
-  cond = tmp;
 
   stmt = VIVI_CODE_IF (vivi_code_if_new (cond));
-  if (if_stmt)
+  g_object_unref (cond);
+  if (if_stmt) {
     vivi_code_if_set_if (stmt, if_stmt);
-  if (else_stmt)
+    g_object_unref (if_stmt);
+  }
+  if (else_stmt) {
     vivi_code_if_set_else (stmt, else_stmt);
+    g_object_unref (else_stmt);
+  }
   return VIVI_CODE_STATEMENT (stmt);
 }
 
commit ad756f706af8c7b95fb19fa4995533fa63c9da8c
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 20:05:46 2008 +0100

    remove debug print

diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index 43161ce..d30e33e 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -209,7 +209,6 @@ vivi_decompiler_state_is_equal (const ViviDecompilerState *a, const ViviDecompil
     vala = walka->data;
     valb = walkb->data;
     
-    g_printerr ("comparison!\n"); 
     if (VIVI_IS_DECOMPILER_UNKNOWN (vala) &&
 	vivi_decompiler_unknown_get_value (VIVI_DECOMPILER_UNKNOWN (vala)) == NULL)
       continue;
commit d6bef05ba74406de4abdbcc99979b1a65bbad524
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 16:40:33 2008 +0100

    don't do "$stack1 = $stack1" assignments

diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index ad6bddf..9cda41f 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -272,16 +272,19 @@ vivi_decompiler_block_add_state_transition (ViviDecompilerBlock *from,
 
   for (i = 0; i < len; i++) {
     ViviCodeValue *name;
+    ViviCodeValue *val_from;
     ViviDecompilerUnknown *val_to = (ViviDecompilerUnknown *) vivi_decompiler_state_peek_nth (to->start, i);
 
     if (!VIVI_IS_DECOMPILER_UNKNOWN (val_to) ||
 	vivi_decompiler_unknown_get_value (val_to))
       continue;
 
-    name = vivi_code_constant_new_string (vivi_decompiler_unknown_get_name (val_to));
-    vivi_code_block_add_statement (block,
-	vivi_code_assignment_new (NULL, name,
-	  vivi_decompiler_state_peek_nth (from->end, i)));
+    val_from = vivi_decompiler_state_peek_nth (from->end, i);
+    if (val_from != VIVI_CODE_VALUE (val_to)) {
+      name = vivi_code_constant_new_string (vivi_decompiler_unknown_get_name (val_to));
+      vivi_code_block_add_statement (block,
+	  vivi_code_assignment_new (NULL, name, val_from));
+    }
   }
 }
 
commit c245c84bd26ea6ddd5287b023469d1477803854a
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 16:38:24 2008 +0100

    large refactoring to allow differing states
    
    This allows correct decompilation of "1 && 2" even though no support for it has
    been added yet.

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index c79d574..d3a1644 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -31,6 +31,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_decompiler_block.c \
 	vivi_decompiler_duplicate.c \
 	vivi_decompiler_state.c \
+	vivi_decompiler_unknown.c \
 	vivi_decompiler.c
 
 noinst_HEADERS = \
@@ -60,6 +61,7 @@ noinst_HEADERS = \
 	vivi_decompiler_block.h \
 	vivi_decompiler_duplicate.h \
 	vivi_decompiler_state.h
+	vivi_decompiler_unknown.h \
 	vivified-compiler.h
 
 
diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index 963c20c..39f3c93 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -109,7 +109,7 @@ vivi_code_block_init (ViviCodeBlock *block)
   block->statements = g_ptr_array_new ();
 }
 
-ViviCodeBlock *
+ViviCodeStatement *
 vivi_code_block_new (void)
 {
   return g_object_new (VIVI_TYPE_CODE_BLOCK, NULL);
diff --git a/vivified/code/vivi_code_block.h b/vivified/code/vivi_code_block.h
index e81ad29..2c397b6 100644
--- a/vivified/code/vivi_code_block.h
+++ b/vivified/code/vivi_code_block.h
@@ -49,7 +49,7 @@ struct _ViviCodeBlockClass
 
 GType			vivi_code_block_get_type		(void);
 
-ViviCodeBlock *		vivi_code_block_new			(void);
+ViviCodeStatement *	vivi_code_block_new			(void);
 
 guint			vivi_code_block_get_n_statements	(ViviCodeBlock *	block);
 ViviCodeStatement *	vivi_code_block_get_statement		(ViviCodeBlock *	block,
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 22185aa..1a2d4ca 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -77,14 +77,22 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
     block_start = vivi_decompiler_block_get_start (block);
     if (block_start < pc) {
       if (vivi_decompiler_block_contains (block, pc)) {
-	vivi_decompiler_block_reset (block);
+	vivi_decompiler_block_reset (block, FALSE);
 	walk = walk->next;
 	break;
       }
       continue;
     }
     if (block_start == pc) {
-      g_printerr ("FIXME: check that the blocks are equal\n");
+      const ViviDecompilerState *block_state = vivi_decompiler_block_get_start_state (block);
+
+      if (!vivi_decompiler_state_is_compatible (block_state, state)) {
+	g_printerr ("incompatible states, the decompiled code will be _really_ fucked up.\n");
+	vivi_decompiler_state_free (state);
+	return block;
+      }
+      if (!vivi_decompiler_state_is_equal (block_state, state))
+	vivi_decompiler_block_reset (block, TRUE);
       vivi_decompiler_state_free (state);
       return block;
     }
@@ -515,12 +523,13 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
   }
   vivi_decompiler_block_finish (block, state);
   if (next_block) {
-    vivi_decompiler_block_set_next (block, next_block);
-  }
-
+    vivi_decompiler_block_set_next (block,
+	vivi_decompiler_push_block_for_state (dec, state));
+  } else {
 out:
 error:
-  vivi_decompiler_state_free (state);
+    vivi_decompiler_state_free (state);
+  }
 }
 
 /*** PROGRAM STRUCTURE ANALYSIS ***/
@@ -583,9 +592,12 @@ vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
   for (walk = ordered; walk; walk = walk->next) {
     current = walk->data;
     next = vivi_decompiler_block_get_next (current);
-    if (walk->next && next == walk->next->data)
-      vivi_decompiler_block_set_next (current, NULL);
-    vivi_decompiler_block_add_to_block (current, block);
+    if (walk->next && next == walk->next->data) {
+      vivi_decompiler_block_add_to_block (current, block);
+      /* FIXME: somehow remove gotos and block forcing */
+    } else {
+      vivi_decompiler_block_add_to_block (current, block);
+    }
     if (next == NULL && walk->next != NULL)
       vivi_code_block_add_statement (block, VIVI_CODE_STATEMENT (vivi_code_return_new ()));
     vivi_decompiler_block_set_next (current, NULL);
@@ -640,7 +652,9 @@ vivi_decompiler_merge_lines (GList **list)
     }
     vivi_decompiler_block_set_next (next, NULL);
     vivi_decompiler_block_set_branch (next, NULL, NULL);
+    vivi_decompiler_block_add_state_transition (block, next, VIVI_CODE_BLOCK (block));
     vivi_decompiler_block_add_to_block (next, VIVI_CODE_BLOCK (block));
+    vivi_decompiler_block_finish (block, vivi_decompiler_block_get_start_state (next));
     *list = vivi_decompiler_purge_block (*list, next);
     result = TRUE;
   }
@@ -648,7 +662,7 @@ vivi_decompiler_merge_lines (GList **list)
   return result;
 }
 
-/*     COND
+/*     CONDi
  *    /    \
  *  [IF] [ELSE]     ==>   BLOCK
  *    \    /
@@ -657,7 +671,8 @@ vivi_decompiler_merge_lines (GList **list)
 static gboolean
 vivi_decompiler_merge_if (GList **list)
 {
-  ViviDecompilerBlock *block, *if_block, *else_block;
+  ViviDecompilerBlock *block, *if_block, *else_block, *next;
+  ViviCodeBlock *b;
   ViviCodeIf *if_stmt;
   ViviCodeStatement *stmt;
   gboolean result;
@@ -693,32 +708,54 @@ vivi_decompiler_merge_if (GList **list)
     /* FINALLY we can merge the blocks */
     if_stmt = VIVI_CODE_IF (vivi_code_if_new (vivi_decompiler_block_get_branch_condition (block)));
     vivi_decompiler_block_set_branch (block, NULL, NULL);
-    vivi_decompiler_block_set_next (block, 
-	vivi_decompiler_block_get_next (if_block ? if_block : else_block));
+    next = vivi_decompiler_block_get_next (if_block ? if_block : else_block);
+    vivi_decompiler_block_set_next (block, next);
+    /* assign the if block */
+    b = VIVI_CODE_BLOCK (vivi_code_block_new ());
     if (if_block) {
-      ViviCodeBlock *tmp = vivi_code_block_new ();
-
       vivi_decompiler_block_set_next (if_block, NULL);
       vivi_decompiler_block_set_branch (if_block, NULL, NULL);
-      vivi_decompiler_block_add_to_block (if_block, tmp);
+      vivi_decompiler_block_add_to_block (if_block, b);
+      vivi_decompiler_block_add_state_transition (if_block, 
+	  vivi_decompiler_block_get_next (block), b);
       *list = vivi_decompiler_purge_block (*list, if_block);
-      vivi_code_if_set_if (if_stmt, VIVI_CODE_STATEMENT (tmp));
+    } else {
+      vivi_decompiler_block_add_state_transition (block, 
+	  vivi_decompiler_block_get_next (block), b);
+    }
+    stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (b));
+    g_object_unref (b);
+    if (stmt) {
+      vivi_code_if_set_if (if_stmt, stmt);
+      g_object_unref (stmt);
     }
+    /* assign the else block */
+    b = VIVI_CODE_BLOCK (vivi_code_block_new ());
     if (else_block) {
-      ViviCodeBlock *tmp = vivi_code_block_new ();
-
       vivi_decompiler_block_set_next (else_block, NULL);
       vivi_decompiler_block_set_branch (else_block, NULL, NULL);
-      vivi_decompiler_block_add_to_block (else_block, tmp);
+      vivi_decompiler_block_add_to_block (else_block, b);
+      vivi_decompiler_block_add_state_transition (else_block, 
+	  vivi_decompiler_block_get_next (block), b);
       *list = vivi_decompiler_purge_block (*list, else_block);
-      vivi_code_if_set_else (if_stmt, VIVI_CODE_STATEMENT (tmp));
+    } else {
+      vivi_decompiler_block_add_state_transition (block, 
+	  vivi_decompiler_block_get_next (block), b);
     }
+    stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (b));
+    g_object_unref (b);
+    if (stmt) {
+      vivi_code_if_set_else (if_stmt, stmt);
+      g_object_unref (stmt);
+    }
+    /* finally finish the if statement */
     stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (if_stmt));
     g_object_unref (if_stmt);
     if (stmt) {
       vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
       g_object_unref (stmt);
     }
+    vivi_decompiler_block_finish (block, vivi_decompiler_block_get_start_state (next));
     result = TRUE;
   }
 
@@ -955,7 +992,8 @@ vivi_decompiler_dump_graphviz (ViviDecompiler *dec)
   string = g_string_new ("digraph G\n{\n");
   g_string_append (string, "  node [ shape = box ]\n");
   for (walk = dec->blocks; walk; walk = walk->next) {
-    g_string_append_printf (string, "  node%p\n", walk->data);
+    g_string_append_printf (string, "  node%p\n", 
+	vivi_decompiler_block_get_start (walk->data));
   }
   g_string_append (string, "\n");
   for (walk = dec->blocks; walk; walk = walk->next) {
@@ -963,11 +1001,17 @@ vivi_decompiler_dump_graphviz (ViviDecompiler *dec)
 
     block = walk->data;
     next = vivi_decompiler_block_get_next (block);
-    if (next)
-      g_string_append_printf (string, "  node%p -> node%p\n", block, next);
+    if (next) {
+      g_string_append_printf (string, "  node%p -> node%p\n", 
+	  vivi_decompiler_block_get_start (block),
+	  vivi_decompiler_block_get_start (next));
+    }
     next = vivi_decompiler_block_get_branch (block);
-    if (next)
-      g_string_append_printf (string, "  node%p -> node%p\n", block, next);
+    if (next) {
+      g_string_append_printf (string, "  node%p -> node%p\n",
+	  vivi_decompiler_block_get_start (block),
+	  vivi_decompiler_block_get_start (next));
+    }
   }
   g_string_append (string, "}\n");
   g_file_set_contents (filename, string->str, string->len, NULL);
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index 4f99498..ad6bddf 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -25,10 +25,14 @@
 #include <swfdec/swfdec_script_internal.h>
 
 #include "vivi_decompiler_block.h"
+#include "vivi_code_assignment.h"
+#include "vivi_code_block.h"
 #include "vivi_code_comment.h"
+#include "vivi_code_constant.h"
 #include "vivi_code_goto.h"
 #include "vivi_code_if.h"
 #include "vivi_code_label.h"
+#include "vivi_decompiler_unknown.h"
 
 G_DEFINE_TYPE (ViviDecompilerBlock, vivi_decompiler_block, VIVI_TYPE_CODE_BLOCK)
 
@@ -38,7 +42,7 @@ vivi_decompiler_block_dispose (GObject *object)
   ViviDecompilerBlock *block = VIVI_DECOMPILER_BLOCK (object);
 
   g_assert (block->incoming == 0);
-  vivi_decompiler_block_reset (block);
+  vivi_decompiler_block_reset (block, FALSE);
   vivi_decompiler_state_free (block->start);
 
   G_OBJECT_CLASS (vivi_decompiler_block_parent_class)->dispose (object);
@@ -67,7 +71,7 @@ vivi_decompiler_block_init (ViviDecompilerBlock *block)
 }
 
 void
-vivi_decompiler_block_reset (ViviDecompilerBlock *block)
+vivi_decompiler_block_reset (ViviDecompilerBlock *block, gboolean generalize_start_state)
 {
   ViviCodeBlock *code_block = VIVI_CODE_BLOCK (block);
   guint i, len;
@@ -83,6 +87,18 @@ vivi_decompiler_block_reset (ViviDecompilerBlock *block)
     vivi_decompiler_state_free (block->end);
     block->end = NULL;
   }
+  if (generalize_start_state) {
+    len = vivi_decompiler_state_get_stack_depth (block->start);
+    for (i = 0; i < len; i++) {
+      g_object_unref (vivi_decompiler_state_pop (block->start));
+    }
+    for (i = 0; i < len; i++) {
+      char *s = g_strdup_printf ("$stack%u", len - i);
+      vivi_decompiler_state_push (block->start,
+	  vivi_decompiler_unknown_new (s));
+      g_free (s);
+    }
+  }
 }
 
 ViviDecompilerBlock *
@@ -217,9 +233,15 @@ vivi_decompiler_block_contains (ViviDecompilerBlock *block, const guint8 *pc)
 void
 vivi_decompiler_block_finish (ViviDecompilerBlock *block, const ViviDecompilerState *state)
 {
-  g_return_if_fail (block->end == NULL);
+  ViviDecompilerState *new;
+
+  g_return_if_fail (VIVI_IS_DECOMPILER_BLOCK (block));
+  g_return_if_fail (state != NULL);
 
-  block->end = vivi_decompiler_state_copy (state);
+  new = vivi_decompiler_state_copy (state);
+  if (block->end)
+    vivi_decompiler_state_free (block->end);
+  block->end = new;
 }
 
 gboolean
@@ -241,6 +263,29 @@ vivi_decompiler_block_get_n_incoming (ViviDecompilerBlock *block)
 }
 
 void
+vivi_decompiler_block_add_state_transition (ViviDecompilerBlock *from,
+    ViviDecompilerBlock *to, ViviCodeBlock *block)
+{
+  guint i, len;
+  
+  len = vivi_decompiler_state_get_stack_depth (to->start);
+
+  for (i = 0; i < len; i++) {
+    ViviCodeValue *name;
+    ViviDecompilerUnknown *val_to = (ViviDecompilerUnknown *) vivi_decompiler_state_peek_nth (to->start, i);
+
+    if (!VIVI_IS_DECOMPILER_UNKNOWN (val_to) ||
+	vivi_decompiler_unknown_get_value (val_to))
+      continue;
+
+    name = vivi_code_constant_new_string (vivi_decompiler_unknown_get_name (val_to));
+    vivi_code_block_add_statement (block,
+	vivi_code_assignment_new (NULL, name,
+	  vivi_decompiler_state_peek_nth (from->end, i)));
+  }
+}
+
+void
 vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
     ViviCodeBlock *target)
 {
@@ -255,9 +300,19 @@ vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
 	vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), i)));
   }
   if (block->branch) {
+    ViviCodeStatement *b;
     stmt = vivi_code_if_new (block->branch_condition);
     vivi_decompiler_block_force_label (block->branch);
+
+    b = vivi_code_block_new ();
+    vivi_decompiler_block_add_state_transition (block, block->branch, VIVI_CODE_BLOCK (b));
     stmt2 = vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (block->branch)));
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (b), stmt2);
+    g_object_unref (stmt2);
+    stmt2 = vivi_code_statement_optimize (b);
+    g_assert (stmt2);
+    g_object_unref (b);
+    
     vivi_code_if_set_if (VIVI_CODE_IF (stmt), stmt2);
     g_object_unref (stmt2);
     vivi_code_block_add_statement (target, stmt);
@@ -265,6 +320,7 @@ vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
   }
   if (block->next) {
     vivi_decompiler_block_force_label (block->next);
+    vivi_decompiler_block_add_state_transition (block, block->next, target);
     stmt = vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (block->next)));
     vivi_code_block_add_statement (target, stmt);
     g_object_unref (stmt);
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
index 828ee80..47a637b 100644
--- a/vivified/code/vivi_decompiler_block.h
+++ b/vivified/code/vivi_decompiler_block.h
@@ -58,7 +58,8 @@ struct _ViviDecompilerBlockClass
 GType			vivi_decompiler_block_get_type   	(void);
 
 ViviDecompilerBlock *	vivi_decompiler_block_new		(ViviDecompilerState *		state);
-void			vivi_decompiler_block_reset		(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_reset		(ViviDecompilerBlock *		block,
+								 gboolean			generalize_start_state);
 
 ViviCodeStatement *	vivi_decompiler_block_get_label		(ViviDecompilerBlock *  	block);
 void			vivi_decompiler_block_force_label	(ViviDecompilerBlock *		block);
@@ -87,6 +88,10 @@ void			vivi_decompiler_block_add_error		(ViviDecompilerBlock *		block,
 
 void			vivi_decompiler_block_add_to_block	(ViviDecompilerBlock *		block,
 								 ViviCodeBlock *		target);
+void			vivi_decompiler_block_add_state_transition 
+								(ViviDecompilerBlock *		from,
+								 ViviDecompilerBlock *		to,
+								 ViviCodeBlock *		block);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_decompiler_duplicate.c b/vivified/code/vivi_decompiler_duplicate.c
new file mode 100644
index 0000000..c5ab825
--- /dev/null
+++ b/vivified/code/vivi_decompiler_duplicate.c
@@ -0,0 +1,87 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_decompiler_duplicate.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviDecompilerDuplicate, vivi_decompiler_duplicate, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_decompiler_duplicate_dispose (GObject *object)
+{
+  ViviDecompilerDuplicate *dupl = VIVI_DECOMPILER_DUPLICATE (object);
+
+  g_object_unref (dupl->value);
+
+  G_OBJECT_CLASS (vivi_decompiler_duplicate_parent_class)->dispose (object);
+}
+
+static void
+vivi_decompiler_duplicate_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviDecompilerDuplicate *dupl = VIVI_DECOMPILER_DUPLICATE (token);
+
+  g_printerr ("FIXME: printing duplicate!\n");
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (dupl->value));
+}
+
+static gboolean
+vivi_decompiler_duplicate_is_constant (ViviCodeValue *value)
+{
+  return vivi_code_value_is_constant (VIVI_DECOMPILER_DUPLICATE (value)->value);
+}
+
+static void
+vivi_decompiler_duplicate_class_init (ViviDecompilerDuplicateClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_decompiler_duplicate_dispose;
+
+  token_class->print = vivi_decompiler_duplicate_print;
+
+  value_class->is_constant = vivi_decompiler_duplicate_is_constant;
+}
+
+static void
+vivi_decompiler_duplicate_init (ViviDecompilerDuplicate *dupl)
+{
+}
+
+ViviCodeValue *
+vivi_decompiler_duplicate_new (ViviCodeValue *value)
+{
+  ViviDecompilerDuplicate *dupl;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  dupl = g_object_new (VIVI_TYPE_DECOMPILER_DUPLICATE, NULL);
+  dupl->value = g_object_ref (value);
+  vivi_code_value_set_precedence (VIVI_CODE_VALUE (dupl), 
+      vivi_code_value_get_precedence (value));
+
+  return VIVI_CODE_VALUE (dupl);
+}
+
diff --git a/vivified/code/vivi_decompiler_duplicate.h b/vivified/code/vivi_decompiler_duplicate.h
new file mode 100644
index 0000000..5b48bb0
--- /dev/null
+++ b/vivified/code/vivi_decompiler_duplicate.h
@@ -0,0 +1,56 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_DUPLICATE_H_
+#define _VIVI_DECOMPILER_DUPLICATE_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompilerDuplicate ViviDecompilerDuplicate;
+typedef struct _ViviDecompilerDuplicateClass ViviDecompilerDuplicateClass;
+
+#define VIVI_TYPE_DECOMPILER_DUPLICATE                    (vivi_decompiler_duplicate_get_type())
+#define VIVI_IS_DECOMPILER_DUPLICATE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER_DUPLICATE))
+#define VIVI_IS_DECOMPILER_DUPLICATE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER_DUPLICATE))
+#define VIVI_DECOMPILER_DUPLICATE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER_DUPLICATE, ViviDecompilerDuplicate))
+#define VIVI_DECOMPILER_DUPLICATE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER_DUPLICATE, ViviDecompilerDuplicateClass))
+#define VIVI_DECOMPILER_DUPLICATE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER_DUPLICATE, ViviDecompilerDuplicateClass))
+
+struct _ViviDecompilerDuplicate
+{
+  ViviCodeValue		parent;
+
+  ViviCodeValue *	value;
+};
+
+struct _ViviDecompilerDuplicateClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_decompiler_duplicate_get_type   	(void);
+
+ViviCodeValue *		vivi_decompiler_duplicate_new		(ViviCodeValue *	value);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index a17127d..43161ce 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -25,6 +25,7 @@
 
 #include "vivi_decompiler_state.h"
 #include "vivi_code_constant.h"
+#include "vivi_decompiler_unknown.h"
 
 struct _ViviDecompilerState {
   SwfdecScript *	script;
@@ -85,6 +86,22 @@ vivi_decompiler_state_pop (ViviDecompilerState *state)
   }
 }
 
+guint
+vivi_decompiler_state_get_stack_depth (const ViviDecompilerState *state)
+{
+  g_return_val_if_fail (state != NULL, 0);
+
+  return g_slist_length (state->stack);
+}
+
+ViviCodeValue *
+vivi_decompiler_state_peek_nth (const ViviDecompilerState *state, guint i)
+{
+  g_return_val_if_fail (state != NULL, NULL);
+
+  return g_slist_nth_data (state->stack, i);
+}
+
 ViviDecompilerState *
 vivi_decompiler_state_copy (const ViviDecompilerState *src)
 {
@@ -146,3 +163,62 @@ vivi_decompiler_state_get_version (const ViviDecompilerState *state)
   return swfdec_script_get_version (state->script);
 }
 
+gboolean
+vivi_decompiler_state_is_compatible (const ViviDecompilerState *a, const ViviDecompilerState *b)
+{
+  g_return_val_if_fail (a != NULL, FALSE);
+  g_return_val_if_fail (b != NULL, FALSE);
+
+  if (a->n_registers != b->n_registers)
+    return FALSE;
+  /* FIXME: check registers */
+  if (a->pool || b->pool) {
+    guint i, len;
+
+    if (a->pool == NULL || b->pool == NULL)
+      return FALSE;
+    len = swfdec_constant_pool_size (a->pool);
+    if (len != swfdec_constant_pool_size (b->pool))
+      return FALSE;
+    for (i = 0; i < len; i++) {
+      if (!g_str_equal (swfdec_constant_pool_get (a->pool, i),
+	    swfdec_constant_pool_get (b->pool, i)))
+	return FALSE;
+    }
+  }
+  /* FIXME: is this necessary? */
+  if (g_slist_length (a->stack) != g_slist_length (b->stack))
+    return FALSE;
+
+  return TRUE;
+}
+
+gboolean
+vivi_decompiler_state_is_equal (const ViviDecompilerState *a, const ViviDecompilerState *b)
+{
+  ViviCodeValue *vala, *valb;
+  GSList *walka, *walkb;
+
+  g_return_val_if_fail (a != NULL, FALSE);
+  g_return_val_if_fail (b != NULL, FALSE);
+
+  if (!vivi_decompiler_state_is_compatible (a, b))
+    return FALSE;
+
+  for (walka = a->stack, walkb = b->stack; walka && walkb; walka = walka->next, walkb = walkb->next) {
+    vala = walka->data;
+    valb = walkb->data;
+    
+    g_printerr ("comparison!\n"); 
+    if (VIVI_IS_DECOMPILER_UNKNOWN (vala) &&
+	vivi_decompiler_unknown_get_value (VIVI_DECOMPILER_UNKNOWN (vala)) == NULL)
+      continue;
+    if (VIVI_IS_DECOMPILER_UNKNOWN (valb) &&
+	vivi_decompiler_unknown_get_value (VIVI_DECOMPILER_UNKNOWN (valb)) == NULL)
+      continue;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
diff --git a/vivified/code/vivi_decompiler_state.h b/vivified/code/vivi_decompiler_state.h
index 6e40b48..990fc81 100644
--- a/vivified/code/vivi_decompiler_state.h
+++ b/vivified/code/vivi_decompiler_state.h
@@ -38,6 +38,10 @@ ViviDecompilerState *		vivi_decompiler_state_copy	(const ViviDecompilerState *	s
 void				vivi_decompiler_state_push	(ViviDecompilerState *		state,
 								 ViviCodeValue *		val);
 ViviCodeValue *			vivi_decompiler_state_pop	(ViviDecompilerState *		state);
+ViviCodeValue *			vivi_decompiler_state_peek_nth	(const ViviDecompilerState *	state,
+								 guint				i);
+guint				vivi_decompiler_state_get_stack_depth
+								(const ViviDecompilerState *  	state);
 ViviCodeValue *			vivi_decompiler_state_get_register (const ViviDecompilerState *	state,
 								 guint				reg);
 
@@ -52,6 +56,13 @@ void				vivi_decompiler_state_set_constant_pool
 guint				vivi_decompiler_state_get_version
 								(const ViviDecompilerState *  	state);
 
+gboolean			vivi_decompiler_state_is_compatible	
+								(const ViviDecompilerState *	a,
+								 const ViviDecompilerState *	b);
+gboolean			vivi_decompiler_state_is_equal	(const ViviDecompilerState *	a,
+								 const ViviDecompilerState *	b);
+
+
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_decompiler_unknown.c b/vivified/code/vivi_decompiler_unknown.c
new file mode 100644
index 0000000..de5e4c5
--- /dev/null
+++ b/vivified/code/vivi_decompiler_unknown.c
@@ -0,0 +1,140 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_decompiler_unknown.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviDecompilerUnknown, vivi_decompiler_unknown, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_decompiler_unknown_dispose (GObject *object)
+{
+  ViviDecompilerUnknown *unknown = VIVI_DECOMPILER_UNKNOWN (object);
+
+  g_free (unknown->name);
+  if (unknown->value)
+    g_object_unref (unknown->value);
+
+  G_OBJECT_CLASS (vivi_decompiler_unknown_parent_class)->dispose (object);
+}
+
+static void
+vivi_decompiler_unknown_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviDecompilerUnknown *unknown = VIVI_DECOMPILER_UNKNOWN (token);
+
+  if (unknown->value) {
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (unknown->value));
+  } else {
+    g_printerr ("FIXME: printing unknown!\n");
+    vivi_code_printer_print (printer, unknown->name);
+  }
+}
+
+static gboolean
+vivi_decompiler_unknown_is_constant (ViviCodeValue *value)
+{
+  ViviDecompilerUnknown *unknown = VIVI_DECOMPILER_UNKNOWN (value);
+  
+  if (unknown->value)
+    return vivi_code_value_is_constant (unknown->value);
+  else
+    return FALSE;
+}
+
+static ViviCodeValue *
+vivi_decompiler_unknown_optimize (ViviCodeValue *value, SwfdecAsValueType hint)
+{
+  ViviDecompilerUnknown *unknown = VIVI_DECOMPILER_UNKNOWN (value);
+  
+  if (unknown->value)
+    return vivi_code_value_optimize (unknown->value, hint);
+  else
+    return g_object_ref (unknown);
+}
+
+static void
+vivi_decompiler_unknown_class_init (ViviDecompilerUnknownClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_decompiler_unknown_dispose;
+
+  token_class->print = vivi_decompiler_unknown_print;
+
+  value_class->is_constant = vivi_decompiler_unknown_is_constant;
+  value_class->optimize = vivi_decompiler_unknown_optimize;
+}
+
+static void
+vivi_decompiler_unknown_init (ViviDecompilerUnknown *unknown)
+{
+  vivi_code_value_set_precedence (VIVI_CODE_VALUE (unknown), VIVI_PRECEDENCE_MEMBER);
+}
+
+ViviCodeValue *
+vivi_decompiler_unknown_new (const char *name)
+{
+  ViviDecompilerUnknown *unknown;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  unknown = g_object_new (VIVI_TYPE_DECOMPILER_UNKNOWN, NULL);
+  unknown->name = g_strdup (name);
+
+  return VIVI_CODE_VALUE (unknown);
+}
+
+void
+vivi_decompiler_unknown_set_value (ViviDecompilerUnknown *unknown, ViviCodeValue *value)
+{
+  g_return_if_fail (VIVI_IS_DECOMPILER_UNKNOWN (unknown));
+  g_return_if_fail (VIVI_IS_CODE_VALUE (value));
+
+  g_object_ref (value);
+  if (unknown->value)
+    g_object_unref (unknown->value);
+  unknown->value = value;
+
+  vivi_code_value_set_precedence (VIVI_CODE_VALUE (unknown),
+      vivi_code_value_get_precedence (value));
+}
+
+ViviCodeValue *
+vivi_decompiler_unknown_get_value (ViviDecompilerUnknown *unknown)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_UNKNOWN (unknown), NULL);
+
+  return unknown->value;
+}
+
+const char *
+vivi_decompiler_unknown_get_name (ViviDecompilerUnknown *unknown)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_UNKNOWN (unknown), NULL);
+
+  return unknown->name;
+}
+
diff --git a/vivified/code/vivi_decompiler_unknown.h b/vivified/code/vivi_decompiler_unknown.h
new file mode 100644
index 0000000..d5ca3b6
--- /dev/null
+++ b/vivified/code/vivi_decompiler_unknown.h
@@ -0,0 +1,62 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_UNKNOWN_H_
+#define _VIVI_DECOMPILER_UNKNOWN_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompilerUnknown ViviDecompilerUnknown;
+typedef struct _ViviDecompilerUnknownClass ViviDecompilerUnknownClass;
+
+#define VIVI_TYPE_DECOMPILER_UNKNOWN                    (vivi_decompiler_unknown_get_type())
+#define VIVI_IS_DECOMPILER_UNKNOWN(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER_UNKNOWN))
+#define VIVI_IS_DECOMPILER_UNKNOWN_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER_UNKNOWN))
+#define VIVI_DECOMPILER_UNKNOWN(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER_UNKNOWN, ViviDecompilerUnknown))
+#define VIVI_DECOMPILER_UNKNOWN_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER_UNKNOWN, ViviDecompilerUnknownClass))
+#define VIVI_DECOMPILER_UNKNOWN_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER_UNKNOWN, ViviDecompilerUnknownClass))
+
+struct _ViviDecompilerUnknown
+{
+  ViviCodeValue		parent;
+
+  char *		name;
+  ViviCodeValue *	value;
+};
+
+struct _ViviDecompilerUnknownClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_decompiler_unknown_get_type   	(void);
+
+ViviCodeValue *		vivi_decompiler_unknown_new		(const char *		name);
+
+void			vivi_decompiler_unknown_set_value	(ViviDecompilerUnknown *unknown,
+								 ViviCodeValue *	value);
+ViviCodeValue *		vivi_decompiler_unknown_get_value	(ViviDecompilerUnknown *unknown);
+const char *		vivi_decompiler_unknown_get_name	(ViviDecompilerUnknown *unknown);
+
+
+G_END_DECLS
+#endif
commit 12003047d5750b2f9e7abea47295f874550e59bc
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 12:37:56 2008 +0100

    save endpc

diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index 6945a6a..4f99498 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -79,7 +79,10 @@ vivi_decompiler_block_reset (ViviDecompilerBlock *block)
   }
   vivi_decompiler_block_set_next (block, NULL);
   vivi_decompiler_block_set_branch (block, NULL, NULL);
-  block->endpc = NULL;
+  if (block->end) {
+    vivi_decompiler_state_free (block->end);
+    block->end = NULL;
+  }
 }
 
 ViviDecompilerBlock *
@@ -202,21 +205,27 @@ vivi_decompiler_block_get_start (ViviDecompilerBlock *block)
 gboolean
 vivi_decompiler_block_contains (ViviDecompilerBlock *block, const guint8 *pc)
 {
-  return pc >= block->startpc && pc < block->endpc;
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_BLOCK (block), FALSE);
+  g_return_val_if_fail (pc != NULL, FALSE);
+
+  if (block->end == NULL)
+    return FALSE;
+
+  return pc >= block->startpc && pc < vivi_decompiler_state_get_pc (block->end);
 }
 
 void
 vivi_decompiler_block_finish (ViviDecompilerBlock *block, const ViviDecompilerState *state)
 {
-  g_return_if_fail (block->endpc == NULL);
+  g_return_if_fail (block->end == NULL);
 
-  block->endpc = vivi_decompiler_state_get_pc (state);
+  block->end = vivi_decompiler_state_copy (state);
 }
 
 gboolean
 vivi_decompiler_block_is_finished (ViviDecompilerBlock *block)
 {
-  return block->endpc != NULL;
+  return block->end != NULL;
 }
 
 const ViviDecompilerState *
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
index a20d0c1..828ee80 100644
--- a/vivified/code/vivi_decompiler_block.h
+++ b/vivified/code/vivi_decompiler_block.h
@@ -44,7 +44,7 @@ struct _ViviDecompilerBlock
   guint			incoming;	/* number of incoming blocks */
   const guint8 *	startpc;	/* pointer to first command in block */
   /* set by parsing the block */
-  const guint8 *	endpc;		/* pointer to after last parsed command or NULL if not parsed yet */
+  ViviDecompilerState *	end;		/* pointer to after last parsed command or NULL if not parsed yet */
   ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
   ViviDecompilerBlock *	branch;		/* NULL or block branched to i if statement */
   ViviCodeValue *	branch_condition;/* NULL or value for deciding if a branch should be taken */
commit 8552b32206371086912944f9692161f3f0b97b82
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 23 12:32:13 2008 +0100

    decompile PushDuplicate

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 23f4958..c79d574 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -29,6 +29,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_value.c \
 	vivi_code_value_statement.c \
 	vivi_decompiler_block.c \
+	vivi_decompiler_duplicate.c \
 	vivi_decompiler_state.c \
 	vivi_decompiler.c
 
@@ -57,6 +58,7 @@ noinst_HEADERS = \
 	vivi_code_value_statement.h \
 	vivi_decompiler.h \
 	vivi_decompiler_block.h \
+	vivi_decompiler_duplicate.h \
 	vivi_decompiler_state.h
 	vivified-compiler.h
 
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index f740d00..22185aa 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -44,6 +44,7 @@
 #include "vivi_code_unary.h"
 #include "vivi_code_value_statement.h"
 #include "vivi_decompiler_block.h"
+#include "vivi_decompiler_duplicate.h"
 #include "vivi_decompiler_state.h"
 
 #if 0
@@ -338,6 +339,20 @@ vivi_decompile_binary (ViviDecompilerBlock *block, ViviDecompilerState *state,
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_duplicate (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *value, *dupl;
+
+  value = vivi_decompiler_state_pop (state);
+  vivi_decompiler_state_push (state, value);
+  dupl = vivi_decompiler_duplicate_new (value);
+  g_object_unref (value);
+  vivi_decompiler_state_push (state, dupl);
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
@@ -345,8 +360,6 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_GET_VARIABLE] = vivi_decompile_get_variable,
   [SWFDEC_AS_ACTION_SET_VARIABLE] = vivi_decompile_set_variable,
   [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
-  [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
-  [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
   [SWFDEC_AS_ACTION_ADD] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_SUBTRACT] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_MULTIPLY] = vivi_decompile_binary,
@@ -360,6 +373,9 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_ADD2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_LESS2] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_EQUALS2] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_PUSH_DUPLICATE] = vivi_decompile_duplicate,
+  [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
+  [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
   [SWFDEC_AS_ACTION_BIT_AND] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_BIT_OR] = vivi_decompile_binary,
   [SWFDEC_AS_ACTION_BIT_XOR] = vivi_decompile_binary,
commit 5b4a1020216a39606b8f51fd1cbb29d492bb81b7
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 22 01:05:07 2008 +0100

    don't forget newline in empty if

diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 7c02756..2459e6c 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -102,6 +102,7 @@ vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
     vivi_code_printer_push_indentation (printer);
     vivi_code_printer_new_line (printer, FALSE);
     vivi_code_printer_print (printer, ";");
+    vivi_code_printer_new_line (printer, FALSE);
     vivi_code_printer_pop_indentation (printer);
   }
   if (stmt->else_statement) {
commit d257fd63a4fb7081d10317ea418278002cec0e63
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 22 01:04:44 2008 +0100

    add another test

diff --git a/vivified/code/test/Makefile.am b/vivified/code/test/Makefile.am
index 13d266c..0bcdc91 100644
--- a/vivified/code/test/Makefile.am
+++ b/vivified/code/test/Makefile.am
@@ -23,6 +23,9 @@ EXTRA_DIST = \
 	if-nested.as \
 	if-nested.swf \
 	if-nested.swf.expect \
+	loop-nested.as \
+	loop-nested.swf \
+	loop-nested.swf.expect \
 	simple-loop.as \
 	simple-loop.swf \
 	simple-loop.swf.expect
diff --git a/vivified/code/test/loop-nested.as b/vivified/code/test/loop-nested.as
new file mode 100644
index 0000000..8a9b2aa
--- /dev/null
+++ b/vivified/code/test/loop-nested.as
@@ -0,0 +1,5 @@
+// makeswf -v 7 -s 200x150 -r 1 -o loop-nested.swf loop-nested.as
+
+while (i > 5)
+  while (j < -10)
+    trace ("Hello");
diff --git a/vivified/code/test/loop-nested.swf b/vivified/code/test/loop-nested.swf
new file mode 100644
index 0000000..79b11d3
Binary files /dev/null and b/vivified/code/test/loop-nested.swf differ
diff --git a/vivified/code/test/loop-nested.swf.expect b/vivified/code/test/loop-nested.swf.expect
new file mode 100644
index 0000000..f23ec3d
--- /dev/null
+++ b/vivified/code/test/loop-nested.swf.expect
@@ -0,0 +1,9 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  while (5 < i)
+    while (j < 10 * -1)
+      trace ("Hello");
+}
+
commit a6b11f684fc46ffc8fea0a2bbfa2a5f481572f67
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 23:48:50 2008 +0100

    unset next/branch when block is written out
    
    makes the decompiler stop crashing due to the new assertion

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 38be5f4..f740d00 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -524,6 +524,16 @@ vivi_decompiler_find_start_block (GList *list, const guint8 *startpc)
   return NULL;
 }
 
+#define ASSERT_BLOCK_LIST(list) \
+  { \
+    GList *_walk; \
+    for (_walk = list; _walk; _walk = _walk->next) { \
+      ViviDecompilerBlock *_block = _walk->data; \
+      g_assert (_block->next == NULL || g_list_find (list, _block->next)); \
+      g_assert (_block->branch == NULL || g_list_find (list, _block->branch)); \
+    } \
+  }
+
 static ViviCodeStatement *
 vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
 {
@@ -531,6 +541,7 @@ vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
   ViviDecompilerBlock *current, *next;
   GList *ordered, *walk;
 
+  //ASSERT_BLOCK_LIST (list);
   current = vivi_decompiler_find_start_block (list, startpc);
 
   ordered = NULL;
@@ -561,6 +572,8 @@ vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
     vivi_decompiler_block_add_to_block (current, block);
     if (next == NULL && walk->next != NULL)
       vivi_code_block_add_statement (block, VIVI_CODE_STATEMENT (vivi_code_return_new ()));
+    vivi_decompiler_block_set_next (current, NULL);
+    vivi_decompiler_block_set_branch (current, NULL, NULL);
   }
   g_list_foreach (ordered, (GFunc) g_object_unref, NULL);
   g_list_free (ordered);
commit f4f7cd2529d69dfd555cd0077f4a05674b294bef
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 23:09:23 2008 +0100

    fix iterating the wrong list
    
    ... by not making it available anymore

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index e6763c5..38be5f4 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -581,7 +581,7 @@ vivi_decompiler_purge_block (GList *list, ViviDecompilerBlock *block)
  *  TWO
  */
 static gboolean
-vivi_decompiler_merge_lines (ViviDecompiler *dec, GList **list)
+vivi_decompiler_merge_lines (GList **list)
 {
   ViviDecompilerBlock *block, *next;
   ViviCodeValue *val;
@@ -626,7 +626,7 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec, GList **list)
  *     NEXT
  */
 static gboolean
-vivi_decompiler_merge_if (ViviDecompiler *dec, GList **list)
+vivi_decompiler_merge_if (GList **list)
 {
   ViviDecompilerBlock *block, *if_block, *else_block;
   ViviCodeIf *if_stmt;
@@ -696,11 +696,11 @@ vivi_decompiler_merge_if (ViviDecompiler *dec, GList **list)
   return result;
 }
 
-static ViviCodeStatement *vivi_decompiler_merge_blocks (ViviDecompiler *dec, 
-    const guint8 *startpc, GList *blocks);
+static ViviCodeStatement *vivi_decompiler_merge_blocks (GList *blocks,
+    const guint8 *startpc);
 
 static gboolean
-vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
+vivi_decompiler_merge_loops (GList **list)
 {
   ViviDecompilerBlock *end, *start, *block, *next;
   ViviCodeBlock *body;
@@ -712,7 +712,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
   guint len;
 
   result = FALSE;
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = *list; walk; walk = walk->next) {
     end = walk->data;
     /* noone has a branch at the end of a loop */
     if (vivi_decompiler_block_get_branch (end))
@@ -876,7 +876,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
 	vivi_decompiler_block_set_next (block, NULL);
       }
     }
-    body = VIVI_CODE_BLOCK (vivi_decompiler_merge_blocks (dec, loop_start, contained));
+    body = VIVI_CODE_BLOCK (vivi_decompiler_merge_blocks (contained, loop_start));
     while ((len = vivi_code_block_get_n_statements (body))) {
       stmt = vivi_code_block_get_statement (body, len - 1);
       if (VIVI_IS_CODE_CONTINUE (stmt)) {
@@ -897,21 +897,18 @@ failed:
 }
 
 static ViviCodeStatement *
-vivi_decompiler_merge_blocks (ViviDecompiler *dec, const guint8 *startpc, GList *blocks)
+vivi_decompiler_merge_blocks (GList *blocks, const guint8 *startpc)
 {
   gboolean restart;
 
-  DUMP_BLOCKS (dec);
-
   do {
     restart = FALSE;
 
-    restart |= vivi_decompiler_merge_lines (dec, &blocks);
-    restart |= vivi_decompiler_merge_if (dec, &blocks);
-    restart |= vivi_decompiler_merge_loops (dec, &blocks);
+    restart |= vivi_decompiler_merge_lines (&blocks);
+    restart |= vivi_decompiler_merge_if (&blocks);
+    restart |= vivi_decompiler_merge_loops (&blocks);
   } while (restart);
 
-  DUMP_BLOCKS (dec);
   return vivi_decompiler_merge_blocks_last_resort (blocks, startpc);
 }
 
@@ -977,7 +974,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
   }
 
   vivi_decompiler_dump_graphviz (dec);
-  stmt = vivi_decompiler_merge_blocks (dec, dec->script->main, dec->blocks);
+  stmt = vivi_decompiler_merge_blocks (dec->blocks, dec->script->main);
   dec->blocks = g_list_prepend (NULL, stmt);
 }
 
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index fac0ac1..6945a6a 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -37,6 +37,7 @@ vivi_decompiler_block_dispose (GObject *object)
 {
   ViviDecompilerBlock *block = VIVI_DECOMPILER_BLOCK (object);
 
+  g_assert (block->incoming == 0);
   vivi_decompiler_block_reset (block);
   vivi_decompiler_state_free (block->start);
 
commit 4083ca83a395d478159c1678bd440d1f25441de5
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 22:52:42 2008 +0100

    fix ordering of block list during decompilation

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 8434182..e6763c5 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -55,7 +55,7 @@ DUMP_BLOCKS (ViviDecompiler *dec)
   g_print ("dumping blocks:\n");
   for (walk = dec->blocks; walk; walk = walk->next) {
     ViviDecompilerBlock *block = walk->data;
-    g_print ("  %p -> %p\n", block->start->pc, block->exitpc);
+    g_print ("  %p -> %p\n", vivi_decompiler_block_get_start (block), block->endpc);
   }
 }
 #else
@@ -77,6 +77,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
     if (block_start < pc) {
       if (vivi_decompiler_block_contains (block, pc)) {
 	vivi_decompiler_block_reset (block);
+	walk = walk->next;
 	break;
       }
       continue;
@@ -91,7 +92,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 
   /* FIXME: see if the block is already there! */
   block = vivi_decompiler_block_new (state);
-  dec->blocks = g_list_insert_before (dec->blocks, walk ? walk->next : NULL, block);
+  dec->blocks = g_list_insert_before (dec->blocks, walk, block);
   return block;
 }
 
commit 67018d3a87323c55a4fc001c5dc5f4d471ffae92
Merge: ca2d72b... f872cef...
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 22:31:14 2008 +0100

    Merge branch 'master' into decompiler

commit ca2d72b443ec22e2bb8c74675dc8ee40f879221f
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 21:49:43 2008 +0100

    use a better mechanism to detect allowed variable names

diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
index f8bcb31..e12c896 100644
--- a/vivified/code/vivi_code_constant.c
+++ b/vivified/code/vivi_code_constant.c
@@ -184,6 +184,8 @@ vivi_code_constant_new_boolean (gboolean boolean)
 char *
 vivi_code_constant_get_variable_name (ViviCodeConstant *constant)
 {
+  static const char *accept = G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "_$";
+
   g_return_val_if_fail (VIVI_IS_CODE_CONSTANT (constant), NULL);
 
   switch (constant->value.type) {
@@ -198,13 +200,9 @@ vivi_code_constant_get_variable_name (ViviCodeConstant *constant)
     case SWFDEC_AS_TYPE_STRING:
       {
 	const char *s = SWFDEC_AS_VALUE_GET_STRING (&constant->value);
-	if (isascii (*s)) {
-	  s++;
-	  while (isalnum (*s))
-	    s++;
-	}
-	if (*s == '\0')
-	  return g_strdup (SWFDEC_AS_VALUE_GET_STRING (&constant->value));
+	gsize len = strspn (s, accept);
+	if (s[len] == '\0')
+	  return g_strdup (s);
 	else
 	  return NULL;
       }
commit 08e215fe82e257dde99cef19fa798f9c0a18b315
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 19:59:20 2008 +0100

    actually fetch registers correctly

diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
index 35e29a5..a17127d 100644
--- a/vivified/code/vivi_decompiler_state.c
+++ b/vivified/code/vivi_decompiler_state.c
@@ -107,10 +107,10 @@ vivi_decompiler_state_copy (const ViviDecompilerState *src)
 ViviCodeValue *
 vivi_decompiler_state_get_register (const ViviDecompilerState *state, guint reg)
 {
-  if (reg >= state->n_registers || state->registers[state->n_registers] == NULL)
+  if (reg >= state->n_registers || state->registers[reg] == NULL)
     return VIVI_CODE_VALUE (vivi_code_constant_new_undefined ());
   else
-    return g_object_ref (state->registers[state->n_registers]);
+    return g_object_ref (state->registers[reg]);
 }
 
 const guint8 *
commit f0a73e3d001dcbd58009b2c14ab799bcecc00abb
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 19:34:05 2008 +0100

    add support for bianry operations

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 7bd4add..23f4958 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -7,6 +7,7 @@ libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
 
 libvivified_compiler_la_SOURCES = \
 	vivi_code_assignment.c \
+	vivi_code_binary.c \
 	vivi_code_block.c \
 	vivi_code_break.c \
 	vivi_code_comment.c \
@@ -33,6 +34,7 @@ libvivified_compiler_la_SOURCES = \
 
 noinst_HEADERS = \
 	vivi_code_assignment.h \
+	vivi_code_binary.c \
 	vivi_code_block.h \
 	vivi_code_break.h \
 	vivi_code_comment.h \
diff --git a/vivified/code/vivi_code_binary.c b/vivified/code/vivi_code_binary.c
new file mode 100644
index 0000000..da71d38
--- /dev/null
+++ b/vivified/code/vivi_code_binary.c
@@ -0,0 +1,137 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <swfdec/swfdec_as_interpret.h>
+
+#include "vivi_code_binary.h"
+#include "vivi_code_printer.h"
+
+static struct {
+  const char *		operation;
+  guint			bytecode;
+  ViviPrecedence	precedence;
+} operation_table[] = {
+  { "add",	SWFDEC_AS_ACTION_ADD,		VIVI_PRECEDENCE_ADD },
+  { "-",	SWFDEC_AS_ACTION_SUBTRACT,	VIVI_PRECEDENCE_ADD },
+  { "*",	SWFDEC_AS_ACTION_MULTIPLY,	VIVI_PRECEDENCE_MULTIPLY },
+  { "/",	SWFDEC_AS_ACTION_DIVIDE,	VIVI_PRECEDENCE_MULTIPLY },
+  { "==",	SWFDEC_AS_ACTION_EQUALS,	VIVI_PRECEDENCE_EQUALITY },
+  { "<",	SWFDEC_AS_ACTION_LESS,		VIVI_PRECEDENCE_RELATIONAL },
+  { "and",	SWFDEC_AS_ACTION_AND,		VIVI_PRECEDENCE_AND },
+  { "or",	SWFDEC_AS_ACTION_OR,		VIVI_PRECEDENCE_OR },
+  { "eq",	SWFDEC_AS_ACTION_STRING_EQUALS,	VIVI_PRECEDENCE_EQUALITY },
+  { "lt",	SWFDEC_AS_ACTION_STRING_LESS,	VIVI_PRECEDENCE_RELATIONAL },
+  { "+",	SWFDEC_AS_ACTION_ADD2,		VIVI_PRECEDENCE_ADD },
+  { "<",	SWFDEC_AS_ACTION_LESS2,		VIVI_PRECEDENCE_RELATIONAL },
+  { "==",	SWFDEC_AS_ACTION_EQUALS2,	VIVI_PRECEDENCE_EQUALITY },
+  { "&",	SWFDEC_AS_ACTION_BIT_AND,	VIVI_PRECEDENCE_BINARY_AND },
+  { "|",	SWFDEC_AS_ACTION_BIT_OR,	VIVI_PRECEDENCE_BINARY_OR },
+  { "^",	SWFDEC_AS_ACTION_BIT_XOR,	VIVI_PRECEDENCE_BINARY_XOR },
+  { "<<",	SWFDEC_AS_ACTION_BIT_LSHIFT,	VIVI_PRECEDENCE_SHIFT },
+  { ">>",	SWFDEC_AS_ACTION_BIT_RSHIFT,	VIVI_PRECEDENCE_SHIFT },
+  { ">>>",	SWFDEC_AS_ACTION_BIT_URSHIFT,	VIVI_PRECEDENCE_SHIFT },
+  { "===",	SWFDEC_AS_ACTION_STRICT_EQUALS,	VIVI_PRECEDENCE_EQUALITY },
+  { ">",	SWFDEC_AS_ACTION_GREATER,	VIVI_PRECEDENCE_RELATIONAL },
+  { "gt",	SWFDEC_AS_ACTION_STRING_GREATER,VIVI_PRECEDENCE_RELATIONAL }
+};
+
+G_DEFINE_TYPE (ViviCodeBinary, vivi_code_binary, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_binary_dispose (GObject *object)
+{
+  ViviCodeBinary *binary = VIVI_CODE_BINARY (object);
+
+  g_object_unref (binary->left);
+  g_object_unref (binary->right);
+
+  G_OBJECT_CLASS (vivi_code_binary_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_binary_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviCodeBinary *binary = VIVI_CODE_BINARY (token);
+
+  vivi_code_printer_print_value (printer, binary->left, 
+      operation_table[binary->operation_index].precedence);
+  vivi_code_printer_print (printer, " ");
+  vivi_code_printer_print (printer, operation_table[binary->operation_index].operation);
+  vivi_code_printer_print (printer, " ");
+  vivi_code_printer_print_value (printer, binary->right, 
+      operation_table[binary->operation_index].precedence);
+}
+
+static gboolean
+vivi_code_binary_is_constant (ViviCodeValue *value)
+{
+  ViviCodeBinary *binary = VIVI_CODE_BINARY (value);
+
+  return vivi_code_value_is_constant (binary->left) &&
+      vivi_code_value_is_constant (binary->right);
+}
+
+static void
+vivi_code_binary_class_init (ViviCodeBinaryClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_binary_dispose;
+
+  token_class->print = vivi_code_binary_print;
+
+  value_class->is_constant = vivi_code_binary_is_constant;
+}
+
+static void
+vivi_code_binary_init (ViviCodeBinary *binary)
+{
+}
+
+ViviCodeValue *
+vivi_code_binary_new_bytecode (ViviCodeValue *left, ViviCodeValue *right, guint code)
+{
+  ViviCodeBinary *binary;
+  guint id;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (left), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (right), NULL);
+  for (id = 0; id < G_N_ELEMENTS (operation_table); id++) {
+    if (operation_table[id].bytecode == code)
+      break;
+  }
+  g_return_val_if_fail (id < G_N_ELEMENTS (operation_table), NULL);
+
+  binary = g_object_new (VIVI_TYPE_CODE_BINARY, NULL);
+  binary->left = g_object_ref (left);
+  binary->right = g_object_ref (right);
+  binary->operation_index = id;
+
+  vivi_code_value_set_precedence (VIVI_CODE_VALUE (binary), 
+      operation_table[id].precedence);
+
+  return VIVI_CODE_VALUE (binary);
+}
+
diff --git a/vivified/code/vivi_code_binary.h b/vivified/code/vivi_code_binary.h
new file mode 100644
index 0000000..f3ea996
--- /dev/null
+++ b/vivified/code/vivi_code_binary.h
@@ -0,0 +1,59 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_BINARY_H_
+#define _VIVI_CODE_BINARY_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeBinary ViviCodeBinary;
+typedef struct _ViviCodeBinaryClass ViviCodeBinaryClass;
+
+#define VIVI_TYPE_CODE_BINARY                    (vivi_code_binary_get_type())
+#define VIVI_IS_CODE_BINARY(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_BINARY))
+#define VIVI_IS_CODE_BINARY_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_BINARY))
+#define VIVI_CODE_BINARY(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_BINARY, ViviCodeBinary))
+#define VIVI_CODE_BINARY_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_BINARY, ViviCodeBinaryClass))
+#define VIVI_CODE_BINARY_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_BINARY, ViviCodeBinaryClass))
+
+struct _ViviCodeBinary
+{
+  ViviCodeValue		parent;
+
+  guint			operation_index;
+  ViviCodeValue *	left;
+  ViviCodeValue *	right;
+};
+
+struct _ViviCodeBinaryClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_binary_get_type   	(void);
+
+ViviCodeValue *		vivi_code_binary_new_bytecode 	(ViviCodeValue *	left,
+							 ViviCodeValue *	right,
+							 guint			code);
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 87720bc..8434182 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -29,6 +29,7 @@
 
 #include "vivi_decompiler.h"
 #include "vivi_code_assignment.h"
+#include "vivi_code_binary.h"
 #include "vivi_code_block.h"
 #include "vivi_code_break.h"
 #include "vivi_code_constant.h"
@@ -321,6 +322,21 @@ vivi_decompile_set_member (ViviDecompilerBlock *block, ViviDecompilerState *stat
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_binary (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *right, *left, *result;
+
+  right = vivi_decompiler_state_pop (state);
+  left = vivi_decompiler_state_pop (state);
+  result = vivi_code_binary_new_bytecode (left, right, code);
+  g_object_unref (left);
+  g_object_unref (right);
+  vivi_decompiler_state_push (state, result);
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
@@ -330,6 +346,28 @@ static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
   [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
   [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
+  [SWFDEC_AS_ACTION_ADD] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_SUBTRACT] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_MULTIPLY] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_DIVIDE] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_EQUALS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_LESS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_AND] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_OR] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_STRING_EQUALS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_STRING_LESS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_ADD2] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_LESS2] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_EQUALS2] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_BIT_AND] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_BIT_OR] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_BIT_XOR] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_BIT_LSHIFT] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_BIT_RSHIFT] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_BIT_URSHIFT] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_STRICT_EQUALS] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_GREATER] = vivi_decompile_binary,
+  [SWFDEC_AS_ACTION_STRING_GREATER] = vivi_decompile_binary,
 
   [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
   [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
commit 65c1106425f20afa28a705aa192a4b9c2cdc17e0
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 18:28:30 2008 +0100

    implement variable get/set without []

diff --git a/vivified/code/vivi_code_assignment.c b/vivified/code/vivi_code_assignment.c
index d06b36f..1b9b444 100644
--- a/vivified/code/vivi_code_assignment.c
+++ b/vivified/code/vivi_code_assignment.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_assignment.h"
+#include "vivi_code_constant.h"
 #include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeAssignment, vivi_code_assignment, VIVI_TYPE_CODE_STATEMENT)
@@ -43,32 +44,38 @@ static void
 vivi_code_assignment_print (ViviCodeToken *token, ViviCodePrinter*printer)
 {
   ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (token);
-  gboolean needs_brackets = TRUE; /* FIXME */
+  char *varname;
+
+  if (VIVI_IS_CODE_CONSTANT (assignment->name))
+    varname = vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (assignment->name));
+  else
+    varname = NULL;
 
   if (assignment->from) {
     vivi_code_printer_print_value (printer, assignment->from, VIVI_PRECEDENCE_MEMBER);
-    if (needs_brackets) {
+    if (varname) {
+      vivi_code_printer_print (printer, ".");
+      vivi_code_printer_print (printer, varname);
+    } else {
       vivi_code_printer_print (printer, "[");
       vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MIN);
       vivi_code_printer_print (printer, "]");
-    } else {
-      vivi_code_printer_print (printer, ".");
-      vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MEMBER);
     }
   } else {
-    if (needs_brackets) {
+    if (varname) {
+      vivi_code_printer_print (printer, varname);
+    } else {
       vivi_code_printer_print (printer, "set (");
       vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MIN);
       vivi_code_printer_print (printer, ", ");
       vivi_code_printer_print_value (printer, assignment->value, VIVI_PRECEDENCE_ASSIGNMENT);
       vivi_code_printer_print (printer, ")");
       goto finalize;
-    } else {
-      vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MEMBER);
     }
   }
   vivi_code_printer_print (printer, " = ");
   vivi_code_printer_print_value (printer, assignment->value, VIVI_PRECEDENCE_ASSIGNMENT);
+  g_free (varname);
 finalize:
   vivi_code_printer_print (printer, ";");
   vivi_code_printer_new_line (printer, FALSE);
diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
index 5f96053..f8bcb31 100644
--- a/vivified/code/vivi_code_constant.c
+++ b/vivified/code/vivi_code_constant.c
@@ -21,6 +21,7 @@
 #include "config.h"
 #endif
 
+#include <ctype.h>
 #include <string.h>
 
 #include "vivi_code_constant.h"
@@ -180,3 +181,38 @@ vivi_code_constant_new_boolean (gboolean boolean)
   return vivi_code_constant_new (&val);
 }
 
+char *
+vivi_code_constant_get_variable_name (ViviCodeConstant *constant)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_CONSTANT (constant), NULL);
+
+  switch (constant->value.type) {
+    case SWFDEC_AS_TYPE_UNDEFINED:
+      return g_strdup ("undefined");
+    case SWFDEC_AS_TYPE_NULL:
+      return g_strdup ("null");
+      break;
+    case SWFDEC_AS_TYPE_BOOLEAN:
+      return g_strdup (SWFDEC_AS_VALUE_GET_BOOLEAN (&constant->value) ? "true" : "false");
+      break;
+    case SWFDEC_AS_TYPE_STRING:
+      {
+	const char *s = SWFDEC_AS_VALUE_GET_STRING (&constant->value);
+	if (isascii (*s)) {
+	  s++;
+	  while (isalnum (*s))
+	    s++;
+	}
+	if (*s == '\0')
+	  return g_strdup (SWFDEC_AS_VALUE_GET_STRING (&constant->value));
+	else
+	  return NULL;
+      }
+    case SWFDEC_AS_TYPE_NUMBER:
+      return NULL;
+    case SWFDEC_AS_TYPE_INT:
+    case SWFDEC_AS_TYPE_OBJECT:
+    default:
+      g_assert_not_reached ();
+  }
+}
diff --git a/vivified/code/vivi_code_constant.h b/vivified/code/vivi_code_constant.h
index 1fe881d..e62e62f 100644
--- a/vivified/code/vivi_code_constant.h
+++ b/vivified/code/vivi_code_constant.h
@@ -51,11 +51,13 @@ GType			vivi_code_constant_get_type   	(void);
 
 ViviCodeValue *		vivi_code_constant_new_null	(void);
 ViviCodeValue *		vivi_code_constant_new_undefined(void);
-ViviCodeValue *		vivi_code_constant_new_string	(const char *	string);
+ViviCodeValue *		vivi_code_constant_new_string	(const char *		string);
 #define vivi_code_constant_new_int vivi_code_constant_new_number
-ViviCodeValue *		vivi_code_constant_new_number	(double		number);
-ViviCodeValue *		vivi_code_constant_new_boolean	(gboolean	boolean);
+ViviCodeValue *		vivi_code_constant_new_number	(double			number);
+ViviCodeValue *		vivi_code_constant_new_boolean	(gboolean		boolean);
 
+char *			vivi_code_constant_get_variable_name
+							(ViviCodeConstant *	constant);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_get.c b/vivified/code/vivi_code_get.c
index 9a87576..7aab6f5 100644
--- a/vivified/code/vivi_code_get.c
+++ b/vivified/code/vivi_code_get.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_get.h"
+#include "vivi_code_constant.h"
 #include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeGet, vivi_code_get, VIVI_TYPE_CODE_VALUE)
@@ -42,27 +43,33 @@ static void
 vivi_code_get_print (ViviCodeToken *token, ViviCodePrinter*printer)
 {
   ViviCodeGet *get = VIVI_CODE_GET (token);
-  gboolean needs_brackets = TRUE; /* FIXME */
+  char *varname;
+
+  if (VIVI_IS_CODE_CONSTANT (get->name))
+    varname = vivi_code_constant_get_variable_name (VIVI_CODE_CONSTANT (get->name));
+  else
+    varname = NULL;
 
   if (get->from) {
     vivi_code_printer_print_value (printer, get->from, VIVI_PRECEDENCE_MEMBER);
-    if (needs_brackets) {
+    if (varname) {
+      vivi_code_printer_print (printer, ".");
+      vivi_code_printer_print (printer, varname);
+    } else {
       vivi_code_printer_print (printer, "[");
       vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MIN);
       vivi_code_printer_print (printer, "]");
-    } else {
-      vivi_code_printer_print (printer, ".");
-      vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MEMBER);
     }
   } else {
-    if (needs_brackets) {
+    if (varname) {
+      vivi_code_printer_print (printer, varname);
+    } else {
       vivi_code_printer_print (printer, "eval (");
       vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MIN);
       vivi_code_printer_print (printer, ")");
-    } else {
-      vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MEMBER);
     }
   }
+  g_free (varname);
 }
 
 static gboolean
commit 7dc08a81f963fbb3233681ce26ff9f009ff73def
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 18:15:35 2008 +0100

    make constants save the real value, not just its string representation

diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
index e432007..5f96053 100644
--- a/vivified/code/vivi_code_constant.c
+++ b/vivified/code/vivi_code_constant.c
@@ -21,6 +21,8 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "vivi_code_constant.h"
 #include "vivi_code_printer.h"
 
@@ -31,17 +33,69 @@ vivi_code_constant_dispose (GObject *object)
 {
   ViviCodeConstant *constant = VIVI_CODE_CONSTANT (object);
 
-  g_free (constant->text);
+  if (SWFDEC_AS_VALUE_IS_STRING (&constant->value))
+    g_free ((char *) SWFDEC_AS_VALUE_GET_STRING (&constant->value));
 
   G_OBJECT_CLASS (vivi_code_constant_parent_class)->dispose (object);
 }
 
+static char *
+escape_string (const char *s)
+{
+  GString *str;
+  char *next;
+
+  str = g_string_new ("\"");
+  while ((next = strpbrk (s, "\"\n"))) {
+    g_string_append_len (str, s, next - s);
+    switch (*next) {
+      case '"':
+	g_string_append (str, "\"");
+	break;
+      case '\n':
+	g_string_append (str, "\n");
+	break;
+      default:
+	g_assert_not_reached ();
+    }
+    s = next + 1;
+  }
+  g_string_append (str, s);
+  g_string_append_c (str, '"');
+  return g_string_free (str, FALSE);
+}
+
 static void
 vivi_code_constant_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeConstant *constant = VIVI_CODE_CONSTANT (token);
-
-  vivi_code_printer_print (printer, constant->text);
+  char *s;
+
+  switch (constant->value.type) {
+    case SWFDEC_AS_TYPE_UNDEFINED:
+      vivi_code_printer_print (printer, "undefined");
+      break;
+    case SWFDEC_AS_TYPE_NULL:
+      vivi_code_printer_print (printer, "null");
+      break;
+    case SWFDEC_AS_TYPE_BOOLEAN:
+      vivi_code_printer_print (printer, SWFDEC_AS_VALUE_GET_BOOLEAN (&constant->value) ? "true" : "false");
+      break;
+    case SWFDEC_AS_TYPE_NUMBER:
+      s = g_strdup_printf ("%.16g", SWFDEC_AS_VALUE_GET_NUMBER (&constant->value));
+      vivi_code_printer_print (printer, s);
+      g_free (s);
+      break;
+    case SWFDEC_AS_TYPE_STRING:
+      s = escape_string (SWFDEC_AS_VALUE_GET_STRING (&constant->value));
+      vivi_code_printer_print (printer, s);
+      g_free (s);
+      break;
+    case SWFDEC_AS_TYPE_INT:
+    case SWFDEC_AS_TYPE_OBJECT:
+    default:
+      g_assert_not_reached ();
+  }
 }
 
 static gboolean
@@ -70,22 +124,59 @@ vivi_code_constant_init (ViviCodeConstant *constant)
   vivi_code_value_set_precedence (VIVI_CODE_VALUE (constant), VIVI_PRECEDENCE_MAX);
 }
 
-ViviCodeToken *
-vivi_code_constant_new (const char *text)
+static ViviCodeValue *
+vivi_code_constant_new (const SwfdecAsValue *value)
 {
   ViviCodeConstant *constant;
 
-  g_return_val_if_fail (text != NULL, NULL);
-
   constant = g_object_new (VIVI_TYPE_CODE_CONSTANT, NULL);
-  constant->text = g_strdup (text);
+  constant->value = *value;
 
-  return VIVI_CODE_TOKEN (constant);
+  return VIVI_CODE_VALUE (constant);
 }
 
-ViviCodeToken *
+ViviCodeValue *
 vivi_code_constant_new_undefined (void)
 {
-  return vivi_code_constant_new ("undefined");
+  SwfdecAsValue val = { 0, };
+  return vivi_code_constant_new (&val);
+}
+
+ViviCodeValue *
+vivi_code_constant_new_null (void)
+{
+  SwfdecAsValue val;
+
+  SWFDEC_AS_VALUE_SET_NULL (&val);
+  return vivi_code_constant_new (&val);
+}
+
+ViviCodeValue *
+vivi_code_constant_new_string (const char *string)
+{
+  SwfdecAsValue val;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  SWFDEC_AS_VALUE_SET_STRING (&val, g_strdup (string));
+  return vivi_code_constant_new (&val);
+}
+
+ViviCodeValue *
+vivi_code_constant_new_number (double number)
+{
+  SwfdecAsValue val;
+
+  SWFDEC_AS_VALUE_SET_NUMBER (&val, number);
+  return vivi_code_constant_new (&val);
+}
+
+ViviCodeValue *
+vivi_code_constant_new_boolean (gboolean boolean)
+{
+  SwfdecAsValue val;
+
+  SWFDEC_AS_VALUE_SET_BOOLEAN (&val, boolean);
+  return vivi_code_constant_new (&val);
 }
 
diff --git a/vivified/code/vivi_code_constant.h b/vivified/code/vivi_code_constant.h
index 72fa113..1fe881d 100644
--- a/vivified/code/vivi_code_constant.h
+++ b/vivified/code/vivi_code_constant.h
@@ -37,9 +37,9 @@ typedef struct _ViviCodeConstantClass ViviCodeConstantClass;
 
 struct _ViviCodeConstant
 {
-  ViviCodeValue		value;
+  ViviCodeValue		parent;
 
-  char *		text;
+  SwfdecAsValue		value;
 };
 
 struct _ViviCodeConstantClass
@@ -49,8 +49,12 @@ struct _ViviCodeConstantClass
 
 GType			vivi_code_constant_get_type   	(void);
 
-ViviCodeToken *		vivi_code_constant_new		(const char *	text);
-ViviCodeToken *		vivi_code_constant_new_undefined(void);
+ViviCodeValue *		vivi_code_constant_new_null	(void);
+ViviCodeValue *		vivi_code_constant_new_undefined(void);
+ViviCodeValue *		vivi_code_constant_new_string	(const char *	string);
+#define vivi_code_constant_new_int vivi_code_constant_new_number
+ViviCodeValue *		vivi_code_constant_new_number	(double		number);
+ViviCodeValue *		vivi_code_constant_new_boolean	(gboolean	boolean);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 256556e..87720bc 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -99,32 +99,6 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 typedef gboolean (* DecompileFunc) (ViviDecompilerBlock *block, ViviDecompilerState *state,
           guint code, const guint8 *data, guint len);
 
-static char *
-escape_string (const char *s)
-{
-  GString *str;
-  char *next;
-
-  str = g_string_new ("\"");
-  while ((next = strpbrk (s, "\"\n"))) {
-    g_string_append_len (str, s, next - s);
-    switch (*next) {
-      case '"':
-	g_string_append (str, "\"");
-	break;
-      case '\n':
-	g_string_append (str, "\n");
-	break;
-      default:
-	g_assert_not_reached ();
-    }
-    s = next + 1;
-  }
-  g_string_append (str, s);
-  g_string_append_c (str, '"');
-  return g_string_free (str, FALSE);
-}
-
 static gboolean
 vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
@@ -132,7 +106,6 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
   ViviCodeValue *val;
   SwfdecBits bits;
   guint type;
-  char *value;
 
   swfdec_bits_init_data (&bits, data, len);
   while (swfdec_bits_left (&bits)) {
@@ -145,33 +118,31 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 	    vivi_decompiler_block_add_error (block, "could not read string");
 	    return TRUE;
 	  }
-	  value = escape_string (s);
+	  val = vivi_code_constant_new_string (s);
 	  g_free (s);
 	  break;
 	}
       case 1: /* float */
-	value = g_strdup_printf ("%f", swfdec_bits_get_float (&bits));
+	val = vivi_code_constant_new_number (swfdec_bits_get_float (&bits));
 	break;
       case 2: /* null */
-	value = g_strdup ("null");
+	val = vivi_code_constant_new_null ();
 	break;
       case 3: /* undefined */
+	val = vivi_code_constant_new_undefined ();
 	break;
       case 4: /* register */
-	{
-	  val = vivi_decompiler_state_get_register (
-		state, swfdec_bits_get_u8 (&bits));
-	  vivi_decompiler_state_push (state, g_object_ref (val));
-	  continue;
-	}
+	val = vivi_decompiler_state_get_register (
+	      state, swfdec_bits_get_u8 (&bits));
+	break;
       case 5: /* boolean */
-	value = g_strdup (swfdec_bits_get_u8 (&bits) ? "true" : "false");
+	val = vivi_code_constant_new_boolean (swfdec_bits_get_u8 (&bits) ? TRUE : FALSE);
 	break;
       case 6: /* double */
-	value = g_strdup_printf ("%g", swfdec_bits_get_double (&bits));
+	val = vivi_code_constant_new_number (swfdec_bits_get_double (&bits));
 	break;
       case 7: /* 32bit int */
-	value = g_strdup_printf ("%d", swfdec_bits_get_u32 (&bits));
+	val = vivi_code_constant_new_int ((int) swfdec_bits_get_u32 (&bits));
 	break;
       case 8: /* 8bit ConstantPool address */
       case 9: /* 16bit ConstantPool address */
@@ -187,14 +158,13 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 		i, swfdec_constant_pool_size (pool));
 	    return TRUE;
 	  }
-	  value = escape_string (swfdec_constant_pool_get (pool, i));
+	  val = vivi_code_constant_new_string (swfdec_constant_pool_get (pool, i));
 	  break;
 	}
       default:
 	vivi_decompiler_block_add_error (block, "Push: type %u not implemented", type);
 	return TRUE;
     }
-    val = VIVI_CODE_VALUE (vivi_code_constant_new (value));
     vivi_decompiler_state_push (state, val);
   }
 
commit 9d01b87103f5129802a6a071619a4f0f138afe68
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 17:47:27 2008 +0100

    implement assignments

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index d5221b7..7bd4add 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -6,6 +6,7 @@ libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
 libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
 
 libvivified_compiler_la_SOURCES = \
+	vivi_code_assignment.c \
 	vivi_code_block.c \
 	vivi_code_break.c \
 	vivi_code_comment.c \
@@ -31,6 +32,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_decompiler.c
 
 noinst_HEADERS = \
+	vivi_code_assignment.h \
 	vivi_code_block.h \
 	vivi_code_break.h \
 	vivi_code_comment.h \
diff --git a/vivified/code/vivi_code_assignment.c b/vivified/code/vivi_code_assignment.c
new file mode 100644
index 0000000..d06b36f
--- /dev/null
+++ b/vivified/code/vivi_code_assignment.c
@@ -0,0 +1,110 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_assignment.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeAssignment, vivi_code_assignment, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_assignment_dispose (GObject *object)
+{
+  ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (object);
+
+  if (assignment->from)
+    g_object_unref (assignment->from);
+  g_object_unref (assignment->name);
+  g_object_unref (assignment->value);
+
+  G_OBJECT_CLASS (vivi_code_assignment_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_assignment_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviCodeAssignment *assignment = VIVI_CODE_ASSIGNMENT (token);
+  gboolean needs_brackets = TRUE; /* FIXME */
+
+  if (assignment->from) {
+    vivi_code_printer_print_value (printer, assignment->from, VIVI_PRECEDENCE_MEMBER);
+    if (needs_brackets) {
+      vivi_code_printer_print (printer, "[");
+      vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MIN);
+      vivi_code_printer_print (printer, "]");
+    } else {
+      vivi_code_printer_print (printer, ".");
+      vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MEMBER);
+    }
+  } else {
+    if (needs_brackets) {
+      vivi_code_printer_print (printer, "set (");
+      vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MIN);
+      vivi_code_printer_print (printer, ", ");
+      vivi_code_printer_print_value (printer, assignment->value, VIVI_PRECEDENCE_ASSIGNMENT);
+      vivi_code_printer_print (printer, ")");
+      goto finalize;
+    } else {
+      vivi_code_printer_print_value (printer, assignment->name, VIVI_PRECEDENCE_MEMBER);
+    }
+  }
+  vivi_code_printer_print (printer, " = ");
+  vivi_code_printer_print_value (printer, assignment->value, VIVI_PRECEDENCE_ASSIGNMENT);
+finalize:
+  vivi_code_printer_print (printer, ";");
+  vivi_code_printer_new_line (printer, FALSE);
+}
+
+static void
+vivi_code_assignment_class_init (ViviCodeAssignmentClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_assignment_dispose;
+
+  token_class->print = vivi_code_assignment_print;
+}
+
+static void
+vivi_code_assignment_init (ViviCodeAssignment *assignment)
+{
+}
+
+ViviCodeStatement *
+vivi_code_assignment_new (ViviCodeValue *from, ViviCodeValue *name, ViviCodeValue *value)
+{
+  ViviCodeAssignment *assignment;
+
+  g_return_val_if_fail (from == NULL || VIVI_IS_CODE_VALUE (from), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  assignment = g_object_new (VIVI_TYPE_CODE_ASSIGNMENT, NULL);
+  if (from)
+    assignment->from = g_object_ref (from);
+  assignment->name = g_object_ref (name);
+  assignment->value = g_object_ref (value);
+
+  return VIVI_CODE_STATEMENT (assignment);
+}
+
diff --git a/vivified/code/vivi_code_assignment.h b/vivified/code/vivi_code_assignment.h
new file mode 100644
index 0000000..ce621a7
--- /dev/null
+++ b/vivified/code/vivi_code_assignment.h
@@ -0,0 +1,61 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_ASSIGNMENT_H_
+#define _VIVI_CODE_ASSIGNMENT_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeAssignment ViviCodeAssignment;
+typedef struct _ViviCodeAssignmentClass ViviCodeAssignmentClass;
+
+#define VIVI_TYPE_CODE_ASSIGNMENT                    (vivi_code_assignment_get_type())
+#define VIVI_IS_CODE_ASSIGNMENT(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_ASSIGNMENT))
+#define VIVI_IS_CODE_ASSIGNMENT_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_ASSIGNMENT))
+#define VIVI_CODE_ASSIGNMENT(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_ASSIGNMENT, ViviCodeAssignment))
+#define VIVI_CODE_ASSIGNMENT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_ASSIGNMENT, ViviCodeAssignmentClass))
+#define VIVI_CODE_ASSIGNMENT_ASSIGNMENT_CLASS(obj)          (G_TYPE_INSTANCE_ASSIGNMENT_CLASS ((obj), VIVI_TYPE_CODE_ASSIGNMENT, ViviCodeAssignmentClass))
+
+struct _ViviCodeAssignment
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeValue *	from;
+  ViviCodeValue *	name;
+  ViviCodeValue	*	value;
+};
+
+struct _ViviCodeAssignmentClass
+{
+  ViviCodeStatementClass	value_class;
+};
+
+GType			vivi_code_assignment_get_type   	(void);
+
+ViviCodeStatement *	vivi_code_assignment_new		(ViviCodeValue *	from,
+								 ViviCodeValue *	name,
+								 ViviCodeValue *	value);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 0326f84..256556e 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -28,6 +28,7 @@
 #include <swfdec/swfdec_script_internal.h>
 
 #include "vivi_decompiler.h"
+#include "vivi_code_assignment.h"
 #include "vivi_code_block.h"
 #include "vivi_code_break.h"
 #include "vivi_code_constant.h"
@@ -316,13 +317,49 @@ vivi_decompile_get_member (ViviDecompilerBlock *block, ViviDecompilerState *stat
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_set_variable (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *name, *value;
+  ViviCodeStatement *assign;
+
+  value = vivi_decompiler_state_pop (state);
+  name = vivi_decompiler_state_pop (state);
+  assign = vivi_code_assignment_new (NULL, name, value);
+  g_object_unref (name);
+  g_object_unref (value);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), assign);
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_set_member (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *from, *name, *value;
+  ViviCodeStatement *assign;
+
+  value = vivi_decompiler_state_pop (state);
+  name = vivi_decompiler_state_pop (state);
+  from = vivi_decompiler_state_pop (state);
+  assign = vivi_code_assignment_new (from, name, value);
+  g_object_unref (from);
+  g_object_unref (name);
+  g_object_unref (value);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), assign);
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
   [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
   [SWFDEC_AS_ACTION_GET_VARIABLE] = vivi_decompile_get_variable,
+  [SWFDEC_AS_ACTION_SET_VARIABLE] = vivi_decompile_set_variable,
   [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
   [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
+  [SWFDEC_AS_ACTION_SET_MEMBER] = vivi_decompile_set_member,
 
   [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
   [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
commit e6fd4264bede3ce338cd66915c8381843506d185
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 16:11:34 2008 +0100

    implement GetVariable and GetMember

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 15fabaa..d5221b7 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -11,6 +11,7 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_comment.c \
 	vivi_code_constant.c \
 	vivi_code_continue.c \
+	vivi_code_get.c \
 	vivi_code_get_url.c \
 	vivi_code_goto.c \
 	vivi_code_if.c \
@@ -35,6 +36,7 @@ noinst_HEADERS = \
 	vivi_code_comment.h \
 	vivi_code_constant.h \
 	vivi_code_continue.h \
+	vivi_code_get.h \
 	vivi_code_get_url.h \
 	vivi_code_goto.h \
 	vivi_code_if.h \
diff --git a/vivified/code/vivi_code_get.c b/vivified/code/vivi_code_get.c
new file mode 100644
index 0000000..9a87576
--- /dev/null
+++ b/vivified/code/vivi_code_get.c
@@ -0,0 +1,111 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_get.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeGet, vivi_code_get, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_get_dispose (GObject *object)
+{
+  ViviCodeGet *get = VIVI_CODE_GET (object);
+
+  if (get->from)
+    g_object_unref (get->from);
+  g_object_unref (get->name);
+
+  G_OBJECT_CLASS (vivi_code_get_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_get_print (ViviCodeToken *token, ViviCodePrinter*printer)
+{
+  ViviCodeGet *get = VIVI_CODE_GET (token);
+  gboolean needs_brackets = TRUE; /* FIXME */
+
+  if (get->from) {
+    vivi_code_printer_print_value (printer, get->from, VIVI_PRECEDENCE_MEMBER);
+    if (needs_brackets) {
+      vivi_code_printer_print (printer, "[");
+      vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MIN);
+      vivi_code_printer_print (printer, "]");
+    } else {
+      vivi_code_printer_print (printer, ".");
+      vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MEMBER);
+    }
+  } else {
+    if (needs_brackets) {
+      vivi_code_printer_print (printer, "eval (");
+      vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MIN);
+      vivi_code_printer_print (printer, ")");
+    } else {
+      vivi_code_printer_print_value (printer, get->name, VIVI_PRECEDENCE_MEMBER);
+    }
+  }
+}
+
+static gboolean
+vivi_code_get_is_constant (ViviCodeValue *value)
+{
+  return FALSE;
+}
+
+static void
+vivi_code_get_class_init (ViviCodeGetClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_get_dispose;
+
+  token_class->print = vivi_code_get_print;
+
+  value_class->is_constant = vivi_code_get_is_constant;
+}
+
+static void
+vivi_code_get_init (ViviCodeGet *get)
+{
+  ViviCodeValue *value = VIVI_CODE_VALUE (get);
+
+  vivi_code_value_set_precedence (value, VIVI_PRECEDENCE_MEMBER);
+}
+
+ViviCodeValue *
+vivi_code_get_new (ViviCodeValue *from, ViviCodeValue *name)
+{
+  ViviCodeGet *get;
+
+  g_return_val_if_fail (from == NULL || VIVI_IS_CODE_VALUE (from), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (name), NULL);
+
+  get = g_object_new (VIVI_TYPE_CODE_GET, NULL);
+  if (from)
+    get->from = g_object_ref (from);
+  get->name = g_object_ref (name);
+
+  return VIVI_CODE_VALUE (get);
+}
+
diff --git a/vivified/code/vivi_code_get.h b/vivified/code/vivi_code_get.h
new file mode 100644
index 0000000..e6c6d6c
--- /dev/null
+++ b/vivified/code/vivi_code_get.h
@@ -0,0 +1,58 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_GET_H_
+#define _VIVI_CODE_GET_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeGet ViviCodeGet;
+typedef struct _ViviCodeGetClass ViviCodeGetClass;
+
+#define VIVI_TYPE_CODE_GET                    (vivi_code_get_get_type())
+#define VIVI_IS_CODE_GET(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_GET))
+#define VIVI_IS_CODE_GET_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_GET))
+#define VIVI_CODE_GET(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_GET, ViviCodeGet))
+#define VIVI_CODE_GET_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_GET, ViviCodeGetClass))
+#define VIVI_CODE_GET_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_GET, ViviCodeGetClass))
+
+struct _ViviCodeGet
+{
+  ViviCodeValue		value;
+
+  ViviCodeValue *	from;
+  ViviCodeValue *	name;
+};
+
+struct _ViviCodeGetClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_get_get_type   	(void);
+
+ViviCodeValue *		vivi_code_get_new		(ViviCodeValue *	from,
+							 ViviCodeValue *	name);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 58fecaa..0326f84 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -32,6 +32,7 @@
 #include "vivi_code_break.h"
 #include "vivi_code_constant.h"
 #include "vivi_code_continue.h"
+#include "vivi_code_get.h"
 #include "vivi_code_get_url.h"
 #include "vivi_code_goto.h"
 #include "vivi_code_if.h"
@@ -287,11 +288,41 @@ vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_get_variable (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *get, *name;
+
+  name = vivi_decompiler_state_pop (state);
+  get = vivi_code_get_new (NULL, name);
+  g_object_unref (name);
+  vivi_decompiler_state_push (state, get);
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_get_member (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *get, *from, *name;
+
+  name = vivi_decompiler_state_pop (state);
+  from = vivi_decompiler_state_pop (state);
+  get = vivi_code_get_new (from, name);
+  g_object_unref (from);
+  g_object_unref (name);
+  vivi_decompiler_state_push (state, get);
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
   [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
-  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
   [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
+  [SWFDEC_AS_ACTION_GET_VARIABLE] = vivi_decompile_get_variable,
+  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
+  [SWFDEC_AS_ACTION_GET_MEMBER] = vivi_decompile_get_member,
 
   [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
   [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
commit a0db9cfc91b5b11089f10bb5cf7aed47a8d6bcf9
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 15:16:26 2008 +0100

    fix expected output for last test

diff --git a/vivified/code/test/simple-loop.swf.expect b/vivified/code/test/simple-loop.swf.expect
index a889eb3..225bac3 100644
--- a/vivified/code/test/simple-loop.swf.expect
+++ b/vivified/code/test/simple-loop.swf.expect
@@ -2,8 +2,7 @@
 
 /* Sprite0_Frame0 */
 {
-  while (false) {
+  while (false)
     trace ("Hello World!");
-  }
 }
 
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 78215d8..58fecaa 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -803,7 +803,6 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
     while ((len = vivi_code_block_get_n_statements (body))) {
       stmt = vivi_code_block_get_statement (body, len - 1);
       if (VIVI_IS_CODE_CONTINUE (stmt)) {
-	g_print ("removing continue stmt\n");
 	vivi_code_block_remove_statement (body, stmt);
       } else {
 	break;
commit deb62ed3e42b1f1999ffb978d9743e9fedfcea9e
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 15:15:30 2008 +0100

    fix refcounting
    
    We now ref all objects when they get set. Previously we took over references.

diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index 6cd6660..963c20c 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -138,6 +138,7 @@ vivi_code_block_insert_statement (ViviCodeBlock *block, guint i, ViviCodeStateme
   g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
   g_return_if_fail (VIVI_IS_CODE_STATEMENT (block));
 
+  g_object_ref (statement);
   if (i >= block->statements->len) {
     g_ptr_array_add (block->statements, statement);
   } else {
diff --git a/vivified/code/vivi_code_get_url.c b/vivified/code/vivi_code_get_url.c
index 1fdaddc..20a12a1 100644
--- a/vivified/code/vivi_code_get_url.c
+++ b/vivified/code/vivi_code_get_url.c
@@ -76,7 +76,7 @@ vivi_code_get_url_init (ViviCodeGetUrl *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_get_url_new (ViviCodeValue *target, ViviCodeValue *url,
     SwfdecLoaderRequest method, gboolean internal, gboolean variables)
 {
@@ -87,12 +87,12 @@ vivi_code_get_url_new (ViviCodeValue *target, ViviCodeValue *url,
   g_return_val_if_fail (method < 4, NULL);
 
   ret = g_object_new (VIVI_TYPE_CODE_GET_URL, NULL);
-  ret->target = target;
-  ret->url = url;
+  ret->target = g_object_ref (target);
+  ret->url = g_object_ref (url);
   ret->method = method;
   ret->internal = internal;
   ret->variables = variables;
 
-  return VIVI_CODE_TOKEN (ret);
+  return VIVI_CODE_STATEMENT (ret);
 }
 
diff --git a/vivified/code/vivi_code_get_url.h b/vivified/code/vivi_code_get_url.h
index fb7e38c..1207a61 100644
--- a/vivified/code/vivi_code_get_url.h
+++ b/vivified/code/vivi_code_get_url.h
@@ -54,7 +54,7 @@ struct _ViviCodeGetUrlClass
 
 GType			vivi_code_get_url_get_type   	(void);
 
-ViviCodeToken *		vivi_code_get_url_new		(ViviCodeValue *	target,
+ViviCodeStatement *	vivi_code_get_url_new		(ViviCodeValue *	target,
 							 ViviCodeValue *	url,
 							 SwfdecLoaderRequest	method,
 							 gboolean		internal,
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 0b5b636..7c02756 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -148,7 +148,7 @@ vivi_code_if_new (ViviCodeValue *condition)
   g_return_val_if_fail (VIVI_IS_CODE_VALUE (condition), NULL);
 
   stmt = g_object_new (VIVI_TYPE_CODE_IF, NULL);
-  stmt->condition = condition;
+  stmt->condition = g_object_ref (condition);
 
   return VIVI_CODE_STATEMENT (stmt);
 }
@@ -159,6 +159,8 @@ vivi_code_if_set_if (ViviCodeIf *if_stmt, ViviCodeStatement *statement)
   g_return_if_fail (VIVI_IS_CODE_IF (if_stmt));
   g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
 
+  if (statement)
+    g_object_ref (statement);
   if (if_stmt->if_statement)
     g_object_unref (if_stmt->if_statement);
   if_stmt->if_statement = statement;
@@ -170,6 +172,8 @@ vivi_code_if_set_else (ViviCodeIf *if_stmt, ViviCodeStatement *statement)
   g_return_if_fail (VIVI_IS_CODE_IF (if_stmt));
   g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
 
+  if (statement)
+    g_object_ref (statement);
   if (if_stmt->else_statement)
     g_object_unref (if_stmt->else_statement);
   if_stmt->else_statement = statement;
diff --git a/vivified/code/vivi_code_loop.c b/vivified/code/vivi_code_loop.c
index f917c8e..fe6aa76 100644
--- a/vivified/code/vivi_code_loop.c
+++ b/vivified/code/vivi_code_loop.c
@@ -98,6 +98,8 @@ vivi_code_loop_set_condition (ViviCodeLoop *loop, ViviCodeValue *condition)
   g_return_if_fail (VIVI_IS_CODE_LOOP (loop));
   g_return_if_fail (VIVI_IS_CODE_VALUE (condition));
 
+  if (condition)
+    g_object_ref (condition);
   if (loop->condition)
     g_object_unref (loop->condition);
   loop->condition = condition;
@@ -109,6 +111,8 @@ vivi_code_loop_set_statement (ViviCodeLoop *loop, ViviCodeStatement *statement)
   g_return_if_fail (VIVI_IS_CODE_LOOP (loop));
   g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
 
+  if (statement)
+    g_object_ref (statement);
   if (loop->statement)
     g_object_unref (loop->statement);
   loop->statement = statement;
diff --git a/vivified/code/vivi_code_trace.c b/vivified/code/vivi_code_trace.c
index e87a728..534e91b 100644
--- a/vivified/code/vivi_code_trace.c
+++ b/vivified/code/vivi_code_trace.c
@@ -63,7 +63,7 @@ vivi_code_trace_init (ViviCodeTrace *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_trace_new (ViviCodeValue *value)
 {
   ViviCodeTrace *trace;
@@ -71,8 +71,8 @@ vivi_code_trace_new (ViviCodeValue *value)
   g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
 
   trace = g_object_new (VIVI_TYPE_CODE_TRACE, NULL);
-  trace->value = value;
+  trace->value = g_object_ref (value);
 
-  return VIVI_CODE_TOKEN (trace);
+  return VIVI_CODE_STATEMENT (trace);
 }
 
diff --git a/vivified/code/vivi_code_trace.h b/vivified/code/vivi_code_trace.h
index 3ce8c37..0591f14 100644
--- a/vivified/code/vivi_code_trace.h
+++ b/vivified/code/vivi_code_trace.h
@@ -50,7 +50,7 @@ struct _ViviCodeTraceClass
 
 GType			vivi_code_trace_get_type   	(void);
 
-ViviCodeToken *		vivi_code_trace_new		(ViviCodeValue *	value);
+ViviCodeStatement *	vivi_code_trace_new		(ViviCodeValue *	value);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
index 5c9414b..858ac1f 100644
--- a/vivified/code/vivi_code_unary.c
+++ b/vivified/code/vivi_code_unary.c
@@ -103,7 +103,7 @@ vivi_code_unary_new (ViviCodeValue *value, char operation)
   g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
 
   unary = g_object_new (VIVI_TYPE_CODE_UNARY, NULL);
-  unary->value = value;
+  unary->value = g_object_ref (value);
   unary->operation = operation;
 
   return VIVI_CODE_VALUE (unary);
diff --git a/vivified/code/vivi_code_value_statement.c b/vivified/code/vivi_code_value_statement.c
index 79e05ce..1b94c57 100644
--- a/vivified/code/vivi_code_value_statement.c
+++ b/vivified/code/vivi_code_value_statement.c
@@ -62,7 +62,7 @@ vivi_code_value_statement_init (ViviCodeValueStatement *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_value_statement_new (ViviCodeValue *value)
 {
   ViviCodeValueStatement *stmt;
@@ -70,8 +70,8 @@ vivi_code_value_statement_new (ViviCodeValue *value)
   g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
 
   stmt = g_object_new (VIVI_TYPE_CODE_VALUE_STATEMENT, NULL);
-  stmt->value = value;
+  stmt->value = g_object_ref (value);
 
-  return VIVI_CODE_TOKEN (stmt);
+  return VIVI_CODE_STATEMENT (stmt);
 }
 
diff --git a/vivified/code/vivi_code_value_statement.h b/vivified/code/vivi_code_value_statement.h
index c506878..8b0a087 100644
--- a/vivified/code/vivi_code_value_statement.h
+++ b/vivified/code/vivi_code_value_statement.h
@@ -50,7 +50,7 @@ struct _ViviCodeValueStatementClass
 
 GType			vivi_code_value_statement_get_type   	(void);
 
-ViviCodeToken *		vivi_code_value_statement_new		(ViviCodeValue *	value);
+ViviCodeStatement *   	vivi_code_value_statement_new		(ViviCodeValue *	value);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 585d714..78215d8 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -203,12 +203,14 @@ static gboolean
 vivi_decompile_pop (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviCodeToken *stmt;
+  ViviCodeStatement *stmt;
   ViviCodeValue *val;
   
   val = vivi_decompiler_state_pop (state);
   stmt = vivi_code_value_statement_new (val);
-  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (stmt));
+  g_object_unref (val);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
+  g_object_unref (stmt);
   return TRUE;
 }
 
@@ -227,12 +229,14 @@ static gboolean
 vivi_decompile_trace (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviCodeToken *trace;
+  ViviCodeStatement *trace;
   ViviCodeValue *val;
   
   val = vivi_decompiler_state_pop (state);
   trace = vivi_code_trace_new (val);
-  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (trace));
+  g_object_unref (val);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), trace);
+  g_object_unref (trace);
   return TRUE;
 }
 
@@ -255,17 +259,18 @@ vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
 
   if (len != 1) {
     vivi_decompiler_block_add_error (block, "invalid length in getURL2 command");   
-    g_object_unref (target);
-    g_object_unref (url);
   } else {
-    ViviCodeToken *token;
+    ViviCodeStatement *stmt;
     guint method = data[0] & 3;
     guint internal = data[0] & 64;
     guint variables = data[0] & 128;
 
-    token = vivi_code_get_url_new (target, url, method, internal, variables);
-    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (token));
+    stmt = vivi_code_get_url_new (target, url, method, internal, variables);
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
+    g_object_unref (stmt);
   }
+  g_object_unref (target);
+  g_object_unref (url);
   return TRUE;
 }
 
@@ -273,11 +278,12 @@ static gboolean
 vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviCodeValue *val;
+  ViviCodeValue *val, *unary;
 
   val = vivi_decompiler_state_pop (state);
-  val = vivi_code_unary_new (val, '!');
-  vivi_decompiler_state_push (state, val);
+  unary = vivi_code_unary_new (val, '!');
+  vivi_decompiler_state_push (state, unary);
+  g_object_unref (val);
   return TRUE;
 }
 
@@ -325,9 +331,8 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	if (vivi_decompiler_block_is_finished (block)) {
 	  vivi_decompiler_block_set_next (block, next);
 	  vivi_decompiler_block_set_branch (block, branch, val);
-	} else {
-	  g_object_unref (val);
 	}
+	g_object_unref (val);
       }
       return FALSE;
     case SWFDEC_AS_ACTION_JUMP:
@@ -525,8 +530,7 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec, GList **list)
     val = vivi_decompiler_block_get_branch_condition (next);
     if (val) {
       vivi_decompiler_block_set_branch (block, 
-	  vivi_decompiler_block_get_branch (next),
-	  g_object_ref (val));
+	  vivi_decompiler_block_get_branch (next), val);
     }
     vivi_decompiler_block_set_next (next, NULL);
     vivi_decompiler_block_set_branch (next, NULL, NULL);
@@ -581,8 +585,7 @@ vivi_decompiler_merge_if (ViviDecompiler *dec, GList **list)
       continue;
 
     /* FINALLY we can merge the blocks */
-    if_stmt = VIVI_CODE_IF (vivi_code_if_new (g_object_ref (
-	  vivi_decompiler_block_get_branch_condition (block))));
+    if_stmt = VIVI_CODE_IF (vivi_code_if_new (vivi_decompiler_block_get_branch_condition (block)));
     vivi_decompiler_block_set_branch (block, NULL, NULL);
     vivi_decompiler_block_set_next (block, 
 	vivi_decompiler_block_get_next (if_block ? if_block : else_block));
@@ -606,8 +609,10 @@ vivi_decompiler_merge_if (ViviDecompiler *dec, GList **list)
     }
     stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (if_stmt));
     g_object_unref (if_stmt);
-    if (stmt)
+    if (stmt) {
       vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
+      g_object_unref (stmt);
+    }
     result = TRUE;
   }
 
@@ -703,14 +708,14 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
 	 (vivi_decompiler_block_get_branch (start) &&
 	  vivi_decompiler_block_get_next (start) == end))) {
       if (vivi_decompiler_block_get_branch (start) == end) {
-	ViviCodeValue *value = vivi_code_unary_new (g_object_ref (
-	    vivi_decompiler_block_get_branch_condition (start)), '!');
+	ViviCodeValue *value = vivi_code_unary_new (
+	    vivi_decompiler_block_get_branch_condition (start), '!');
 	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop),
 	    vivi_code_value_optimize (value, SWFDEC_AS_TYPE_BOOLEAN));
 	g_object_unref (value);
       } else {
-	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop), g_object_ref (
-	    vivi_decompiler_block_get_branch_condition (start)));
+	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop), 
+	    vivi_decompiler_block_get_branch_condition (start));
 	vivi_decompiler_block_set_next (start,
 	    vivi_decompiler_block_get_branch (start));
       }
@@ -805,6 +810,8 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       }
     }
     vivi_code_loop_set_statement (VIVI_CODE_LOOP (loop), VIVI_CODE_STATEMENT (body));
+    g_object_unref (body);
+    g_object_unref (loop);
 
     return TRUE;
 failed:
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index b589658..fac0ac1 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -126,6 +126,7 @@ vivi_decompiler_block_force_label (ViviDecompilerBlock *block)
   stmt = vivi_code_label_new (s);
   g_free (s);
   vivi_code_block_insert_statement (VIVI_CODE_BLOCK (block), 0, stmt);
+  g_object_unref (stmt);
 }
 
 void
@@ -150,14 +151,16 @@ vivi_decompiler_block_set_branch (ViviDecompilerBlock *block, ViviDecompilerBloc
 {
   g_return_if_fail ((branch != NULL) ^ (branch_condition == NULL));
 
+  if (branch) {
+    g_object_ref (branch_condition);
+    branch->incoming++;
+  }
   if (block->branch) {
     block->branch->incoming--;
     g_object_unref (block->branch_condition);
   }
   block->branch = branch;
   block->branch_condition = branch_condition;
-  if (branch)
-    branch->incoming++;
 }
 
 ViviDecompilerBlock *
@@ -231,6 +234,7 @@ void
 vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
     ViviCodeBlock *target)
 {
+  ViviCodeStatement *stmt, *stmt2;
   guint i;
 
   g_return_if_fail (VIVI_IS_DECOMPILER_BLOCK (block));
@@ -241,18 +245,19 @@ vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
 	vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), i)));
   }
   if (block->branch) {
-    ViviCodeStatement *stmt = vivi_code_if_new (
-	g_object_ref (block->branch_condition));
+    stmt = vivi_code_if_new (block->branch_condition);
     vivi_decompiler_block_force_label (block->branch);
-    vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (
-	  vivi_code_goto_new (g_object_ref (
-		vivi_decompiler_block_get_label (block->branch)))));
+    stmt2 = vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (block->branch)));
+    vivi_code_if_set_if (VIVI_CODE_IF (stmt), stmt2);
+    g_object_unref (stmt2);
     vivi_code_block_add_statement (target, stmt);
+    g_object_unref (stmt);
   }
   if (block->next) {
     vivi_decompiler_block_force_label (block->next);
-    vivi_code_block_add_statement (target, vivi_code_goto_new (g_object_ref (
-	vivi_decompiler_block_get_label (block->next))));
+    stmt = vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (block->next)));
+    vivi_code_block_add_statement (target, stmt);
+    g_object_unref (stmt);
   }
 }
 
commit b839db01714cccc8f3b347aa39e7c273f8b75d23
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 14:53:32 2008 +0100

    make continue statements work

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index cfec8de..585d714 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -730,6 +730,8 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
 	  walk2->data = block;
 	  continue;
 	}
+	if (g_list_find (contained, walk2->data))
+	  continue;
 	if (vivi_decompiler_block_get_branch (walk2->data) == start)
 	  vivi_decompiler_block_set_branch (walk2->data, block,
 	      g_object_ref (vivi_decompiler_block_get_branch_condition (walk2->data)));
@@ -744,7 +746,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       block = walk2->data;
       *list = g_list_remove (*list, block);
       next = vivi_decompiler_block_get_branch (block);
-      if (next && !g_list_find (contained, next)) {
+      if (next != NULL && (!g_list_find (contained, next) || next == start)) {
 	stmt = vivi_code_if_new (g_object_ref (vivi_decompiler_block_get_branch_condition (block)));
 	if (next == start) {
 	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_continue_new ());
@@ -759,7 +761,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
 	vivi_decompiler_block_set_branch (block, NULL, NULL);
       }
       next = vivi_decompiler_block_get_next (block);
-      if (next && !g_list_find (contained, next)) {
+      if (next != NULL && (!g_list_find (contained, next) || next == start)) {
 	if (next == start) {
 	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), vivi_code_continue_new ());
 	} else if (next == end) {
commit db78ec976f99c0dc92989e30e6c0966421747eb5
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 14:42:23 2008 +0100

    auto-remove continue statement from the end of loops

diff --git a/vivified/code/vivi_code_goto.c b/vivified/code/vivi_code_goto.c
index 44e7f32..60301f8 100644
--- a/vivified/code/vivi_code_goto.c
+++ b/vivified/code/vivi_code_goto.c
@@ -63,7 +63,7 @@ vivi_code_goto_init (ViviCodeGoto *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_goto_new (ViviCodeLabel *label)
 {
   ViviCodeGoto *gotoo;
@@ -73,6 +73,6 @@ vivi_code_goto_new (ViviCodeLabel *label)
   gotoo = g_object_new (VIVI_TYPE_CODE_GOTO, NULL);
   gotoo->label = g_object_ref (label);
 
-  return VIVI_CODE_TOKEN (gotoo);
+  return VIVI_CODE_STATEMENT (gotoo);
 }
 
diff --git a/vivified/code/vivi_code_goto.h b/vivified/code/vivi_code_goto.h
index b220600..6cbde87 100644
--- a/vivified/code/vivi_code_goto.h
+++ b/vivified/code/vivi_code_goto.h
@@ -50,7 +50,7 @@ struct _ViviCodeGotoClass
 
 GType			vivi_code_goto_get_type   	(void);
 
-ViviCodeToken *		vivi_code_goto_new		(ViviCodeLabel *	label);
+ViviCodeStatement *	vivi_code_goto_new		(ViviCodeLabel *	label);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index b289ded..0b5b636 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -140,7 +140,7 @@ vivi_code_if_init (ViviCodeIf *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_if_new (ViviCodeValue *condition)
 {
   ViviCodeIf *stmt;
@@ -150,7 +150,7 @@ vivi_code_if_new (ViviCodeValue *condition)
   stmt = g_object_new (VIVI_TYPE_CODE_IF, NULL);
   stmt->condition = condition;
 
-  return VIVI_CODE_TOKEN (stmt);
+  return VIVI_CODE_STATEMENT (stmt);
 }
 
 void
diff --git a/vivified/code/vivi_code_if.h b/vivified/code/vivi_code_if.h
index aba0b40..8a8b23e 100644
--- a/vivified/code/vivi_code_if.h
+++ b/vivified/code/vivi_code_if.h
@@ -52,7 +52,7 @@ struct _ViviCodeIfClass
 
 GType			vivi_code_if_get_type   	(void);
 
-ViviCodeToken *		vivi_code_if_new		(ViviCodeValue *	condition);
+ViviCodeStatement *	vivi_code_if_new		(ViviCodeValue *	condition);
 void			vivi_code_if_set_if		(ViviCodeIf *		if_stmt,
 							 ViviCodeStatement *	statement);
 void		  	vivi_code_if_set_else		(ViviCodeIf *		if_stmt,
diff --git a/vivified/code/vivi_code_loop.c b/vivified/code/vivi_code_loop.c
index 78c9048..f917c8e 100644
--- a/vivified/code/vivi_code_loop.c
+++ b/vivified/code/vivi_code_loop.c
@@ -86,7 +86,7 @@ vivi_code_loop_init (ViviCodeLoop *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_loop_new (void)
 {
   return g_object_new (VIVI_TYPE_CODE_LOOP, NULL);
diff --git a/vivified/code/vivi_code_loop.h b/vivified/code/vivi_code_loop.h
index d8742a9..1453f9a 100644
--- a/vivified/code/vivi_code_loop.h
+++ b/vivified/code/vivi_code_loop.h
@@ -51,7 +51,7 @@ struct _ViviCodeLoopClass
 
 GType			vivi_code_loop_get_type   	(void);
 
-ViviCodeToken *		vivi_code_loop_new		(void);
+ViviCodeStatement *	vivi_code_loop_new		(void);
 void			vivi_code_loop_set_condition	(ViviCodeLoop *		loop,
 							 ViviCodeValue *	condition);
 void			vivi_code_loop_set_statement	(ViviCodeLoop *		loop,
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 0f93e28..cfec8de 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -621,11 +621,13 @@ static gboolean
 vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
 {
   ViviDecompilerBlock *end, *start, *block, *next;
+  ViviCodeBlock *body;
   gboolean result;
   GList *walk, *walk2;
   const guint8 *loop_start, *loop_end;
   GList *contained, *to_check;
-  ViviCodeToken *loop;
+  ViviCodeStatement *loop, *stmt;
+  guint len;
 
   result = FALSE;
   for (walk = dec->blocks; walk; walk = walk->next) {
@@ -655,7 +657,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
     /* this is just a rough guess for now */
     loop_end = vivi_decompiler_block_get_start (end);
     /* let's find the rest of the loop */
-    to_check = g_list_prepend (contained, start);
+    to_check = g_list_prepend (NULL, start);
     contained = NULL;
     while (to_check) {
       block = to_check->data;
@@ -743,8 +745,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       *list = g_list_remove (*list, block);
       next = vivi_decompiler_block_get_branch (block);
       if (next && !g_list_find (contained, next)) {
-	ViviCodeStatement *stmt = VIVI_CODE_STATEMENT (vivi_code_if_new (
-	    g_object_ref (vivi_decompiler_block_get_branch_condition (block))));
+	stmt = vivi_code_if_new (g_object_ref (vivi_decompiler_block_get_branch_condition (block)));
 	if (next == start) {
 	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_continue_new ());
 	} else if (next == end) {
@@ -776,8 +777,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       block = walk2->data;
       next = vivi_decompiler_block_get_branch (block);
       if (next && !g_list_find (*list, next)) {
-	ViviCodeStatement *stmt = VIVI_CODE_STATEMENT (vivi_code_if_new (
-	    g_object_ref (vivi_decompiler_block_get_branch_condition (block))));
+	stmt = vivi_code_if_new (g_object_ref (vivi_decompiler_block_get_branch_condition (block)));
 	vivi_decompiler_block_force_label (next);
 	vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (vivi_code_goto_new (
 	      VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
@@ -792,8 +792,17 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
 	vivi_decompiler_block_set_next (block, NULL);
       }
     }
-    vivi_code_loop_set_statement (VIVI_CODE_LOOP (loop), vivi_decompiler_merge_blocks (dec, loop_start,
-	  contained));
+    body = VIVI_CODE_BLOCK (vivi_decompiler_merge_blocks (dec, loop_start, contained));
+    while ((len = vivi_code_block_get_n_statements (body))) {
+      stmt = vivi_code_block_get_statement (body, len - 1);
+      if (VIVI_IS_CODE_CONTINUE (stmt)) {
+	g_print ("removing continue stmt\n");
+	vivi_code_block_remove_statement (body, stmt);
+      } else {
+	break;
+      }
+    }
+    vivi_code_loop_set_statement (VIVI_CODE_LOOP (loop), VIVI_CODE_STATEMENT (body));
 
     return TRUE;
 failed:
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index 2e544df..b589658 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -241,19 +241,18 @@ vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
 	vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), i)));
   }
   if (block->branch) {
-    ViviCodeToken *token = vivi_code_if_new (
+    ViviCodeStatement *stmt = vivi_code_if_new (
 	g_object_ref (block->branch_condition));
     vivi_decompiler_block_force_label (block->branch);
-    vivi_code_if_set_if (VIVI_CODE_IF (token), VIVI_CODE_STATEMENT (
+    vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (
 	  vivi_code_goto_new (g_object_ref (
 		vivi_decompiler_block_get_label (block->branch)))));
-    vivi_code_block_add_statement (target, VIVI_CODE_STATEMENT (token));
+    vivi_code_block_add_statement (target, stmt);
   }
   if (block->next) {
     vivi_decompiler_block_force_label (block->next);
-    vivi_code_block_add_statement (target, VIVI_CODE_STATEMENT (
-	  vivi_code_goto_new (g_object_ref (
-	      vivi_decompiler_block_get_label (block->next)))));
+    vivi_code_block_add_statement (target, vivi_code_goto_new (g_object_ref (
+	vivi_decompiler_block_get_label (block->next))));
   }
 }
 
commit a3b88cdbcc5005946c2f75b2703d8eedd081f96a
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 14:35:25 2008 +0100

    fix refcounting

diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index b6827dd..6cd6660 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -155,7 +155,9 @@ vivi_code_block_remove_statement (ViviCodeBlock *block, ViviCodeStatement *state
   g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
   g_return_if_fail (VIVI_IS_CODE_STATEMENT (block));
 
-  if (!g_ptr_array_remove (block->statements, statement))
+  if (g_ptr_array_remove (block->statements, statement))
+    g_object_unref (statement);
+  else
     g_return_if_reached ();
 }
 
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index b9bf0d5..2e544df 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -237,8 +237,8 @@ vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
   g_return_if_fail (VIVI_IS_CODE_BLOCK (target));
 
   for (i = 0; i < vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (block)); i++) {
-    vivi_code_block_add_statement (target, 
-	vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), i));
+    vivi_code_block_add_statement (target, g_object_ref (
+	vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), i)));
   }
   if (block->branch) {
     ViviCodeToken *token = vivi_code_if_new (
commit f110fc3dde6b7dec72bd0a225a1ac8700773eeac
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 14:19:45 2008 +0100

    add a first loop test
    
    surprisingly, it doesn't work yet

diff --git a/vivified/code/test/Makefile.am b/vivified/code/test/Makefile.am
index f6581d6..13d266c 100644
--- a/vivified/code/test/Makefile.am
+++ b/vivified/code/test/Makefile.am
@@ -22,5 +22,8 @@ EXTRA_DIST = \
 	if.swf.expect \
 	if-nested.as \
 	if-nested.swf \
-	if-nested.swf.expect
+	if-nested.swf.expect \
+	simple-loop.as \
+	simple-loop.swf \
+	simple-loop.swf.expect
 
diff --git a/vivified/code/test/simple-loop.as b/vivified/code/test/simple-loop.as
new file mode 100644
index 0000000..05e5c72
--- /dev/null
+++ b/vivified/code/test/simple-loop.as
@@ -0,0 +1,5 @@
+// makeswf -v 7 -s 200x150 -r 1 -o simple-loop.swf simple-loop.as
+
+while (false) {
+  trace ("Hello World!");
+}
diff --git a/vivified/code/test/simple-loop.swf b/vivified/code/test/simple-loop.swf
new file mode 100644
index 0000000..88ccee5
Binary files /dev/null and b/vivified/code/test/simple-loop.swf differ
diff --git a/vivified/code/test/simple-loop.swf.expect b/vivified/code/test/simple-loop.swf.expect
new file mode 100644
index 0000000..a889eb3
--- /dev/null
+++ b/vivified/code/test/simple-loop.swf.expect
@@ -0,0 +1,9 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  while (false) {
+    trace ("Hello World!");
+  }
+}
+
commit 87ba6ca9314ad3dede3266876239a532e0de2217
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 13:59:49 2008 +0100

    rewrite ViviCodeBlock to use a GPtrArray instead of a GQueue
    
    also give it all the necessary API it needs

diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index 52dd476..b6827dd 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -35,9 +35,12 @@ static void
 vivi_code_block_dispose (GObject *object)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (object);
+  guint i;
 
-  g_queue_foreach (block->statements, (GFunc) g_object_unref, NULL);
-  g_queue_free (block->statements);
+  for (i = 0; i < block->statements->len; i++) {
+    g_object_unref (g_ptr_array_index (block->statements, i));
+  }
+  g_ptr_array_free (block->statements, TRUE);
 
   G_OBJECT_CLASS (vivi_code_block_parent_class)->dispose (object);
 }
@@ -46,11 +49,11 @@ static ViviCodeStatement *
 vivi_code_block_optimize (ViviCodeStatement *stmt)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (stmt);
-  guint length;
 
-  length = g_queue_get_length (block->statements);
-  if (length == 0)
+  if (block->statements->len == 0)
     return NULL;
+  if (block->statements->len == 1)
+    return g_object_ref (g_ptr_array_index (block->statements, 0));
 
   return g_object_ref (block);
 }
@@ -59,15 +62,13 @@ static gboolean
 vivi_code_block_needs_braces (ViviCodeStatement *stmt)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (stmt);
-  GList *first;
-
-  first = g_queue_peek_head_link (block->statements);
 
-  if (first == NULL)
+  if (block->statements->len == 0)
     return FALSE;
-  if (first->next)
+  if (block->statements->len > 1)
     return TRUE;
-  return vivi_code_statement_needs_braces (first->data);
+
+  return vivi_code_statement_needs_braces (g_ptr_array_index (block->statements, 0));
 }
 
 static void
@@ -75,14 +76,14 @@ vivi_code_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (token);
 
-  if (g_queue_is_empty (block->statements)) {
+  if (block->statements->len == 0) {
     vivi_code_printer_print (printer, ";");
     vivi_code_printer_new_line (printer, FALSE);
   } else {
-    GList *walk;
+    guint i;
 
-    for (walk = g_queue_peek_head_link (block->statements); walk; walk = walk->next) {
-      vivi_code_printer_print_token (printer, walk->data);
+    for (i = 0; i < block->statements->len; i++) {
+      vivi_code_printer_print_token (printer, g_ptr_array_index (block->statements, i));
     }
   }
 }
@@ -105,7 +106,7 @@ vivi_code_block_class_init (ViviCodeBlockClass *klass)
 static void
 vivi_code_block_init (ViviCodeBlock *block)
 {
-  block->statements = g_queue_new ();
+  block->statements = g_ptr_array_new ();
 }
 
 ViviCodeBlock *
@@ -114,30 +115,47 @@ vivi_code_block_new (void)
   return g_object_new (VIVI_TYPE_CODE_BLOCK, NULL);
 }
 
-void
-vivi_code_block_prepend_statement (ViviCodeBlock *block,
-    ViviCodeStatement *statement)
+guint
+vivi_code_block_get_n_statements (ViviCodeBlock *block)
 {
-  g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
-  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+  g_return_val_if_fail (VIVI_IS_CODE_BLOCK (block), 0);
+
+  return block->statements->len;
+}
 
-  g_queue_push_head (block->statements, statement);
+ViviCodeStatement *
+vivi_code_block_get_statement (ViviCodeBlock *block, guint i)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_BLOCK (block), NULL);
+  g_return_val_if_fail (i < block->statements->len, NULL);
+
+  return g_ptr_array_index (block->statements, i);
 }
+
 void
-vivi_code_block_add_statement (ViviCodeBlock *block,
-    ViviCodeStatement *statement)
+vivi_code_block_insert_statement (ViviCodeBlock *block, guint i, ViviCodeStatement *statement)
 {
   g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
-  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (block));
 
-  g_queue_push_tail (block->statements, statement);
+  if (i >= block->statements->len) {
+    g_ptr_array_add (block->statements, statement);
+  } else {
+    guint after = block->statements->len - i;
+    g_ptr_array_set_size (block->statements, block->statements->len + 1);
+    memmove (&g_ptr_array_index (block->statements, i + 1),
+	&g_ptr_array_index (block->statements, i), sizeof (gpointer) * after);
+    g_ptr_array_index (block->statements, i) = statement;
+  }
 }
 
-guint
-vivi_code_block_get_n_statements (ViviCodeBlock *block)
+void
+vivi_code_block_remove_statement (ViviCodeBlock *block, ViviCodeStatement *statement)
 {
-  g_return_val_if_fail (VIVI_IS_CODE_BLOCK (block), 0);
+  g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (block));
 
-  return g_queue_get_length (block->statements);
+  if (!g_ptr_array_remove (block->statements, statement))
+    g_return_if_reached ();
 }
 
diff --git a/vivified/code/vivi_code_block.h b/vivified/code/vivi_code_block.h
index b5ce572..e81ad29 100644
--- a/vivified/code/vivi_code_block.h
+++ b/vivified/code/vivi_code_block.h
@@ -39,7 +39,7 @@ struct _ViviCodeBlock
 {
   ViviCodeStatement	statement;
 
-  GQueue *		statements;	/* ViviCodeStatements inside this block */
+  GPtrArray *		statements;	/* ViviCodeStatements inside this block */
 };
 
 struct _ViviCodeBlockClass
@@ -51,11 +51,15 @@ GType			vivi_code_block_get_type		(void);
 
 ViviCodeBlock *		vivi_code_block_new			(void);
 
-void			vivi_code_block_prepend_statement   	(ViviCodeBlock *	block,
+guint			vivi_code_block_get_n_statements	(ViviCodeBlock *	block);
+ViviCodeStatement *	vivi_code_block_get_statement		(ViviCodeBlock *	block,
+								 guint			i);
+#define vivi_code_block_add_statement(block, stmt) vivi_code_block_insert_statement (block, G_MAXUINT, stmt)
+void			vivi_code_block_insert_statement   	(ViviCodeBlock *	block,
+								 guint			i,
 								 ViviCodeStatement *	statement);
-void			vivi_code_block_add_statement   	(ViviCodeBlock *	block,
+void			vivi_code_block_remove_statement	(ViviCodeBlock *	block,
 								 ViviCodeStatement *	statement);
-guint			vivi_code_block_get_n_statements	(ViviCodeBlock *	block);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_code_label.c b/vivified/code/vivi_code_label.c
index 6813f2d..d84a9ad 100644
--- a/vivified/code/vivi_code_label.c
+++ b/vivified/code/vivi_code_label.c
@@ -63,7 +63,7 @@ vivi_code_label_init (ViviCodeLabel *token)
 {
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_code_label_new (const char *name)
 {
   ViviCodeLabel *label;
@@ -73,7 +73,7 @@ vivi_code_label_new (const char *name)
   label = g_object_new (VIVI_TYPE_CODE_LABEL, NULL);
   label->name = g_strdup (name);
 
-  return VIVI_CODE_TOKEN (label);
+  return VIVI_CODE_STATEMENT (label);
 }
 
 const char *
diff --git a/vivified/code/vivi_code_label.h b/vivified/code/vivi_code_label.h
index f79dc04..342e728 100644
--- a/vivified/code/vivi_code_label.h
+++ b/vivified/code/vivi_code_label.h
@@ -49,7 +49,7 @@ struct _ViviCodeLabelClass
 
 GType			vivi_code_label_get_type   	(void);
 
-ViviCodeToken *		vivi_code_label_new		(const char *		name);
+ViviCodeStatement *	vivi_code_label_new		(const char *		name);
 
 const char *		vivi_code_label_get_name	(ViviCodeLabel *	label);
 
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 90ea281..0f93e28 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -652,7 +652,6 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
      * it is and go from there.
      */
     loop_start = vivi_decompiler_block_get_start (start);
-    g_print ("found a loop starting at %p\n", loop_start);
     /* this is just a rough guess for now */
     loop_end = vivi_decompiler_block_get_start (end);
     /* let's find the rest of the loop */
@@ -663,7 +662,6 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       to_check = g_list_remove (to_check, block);
       /* jump to before start?! */
       if (vivi_decompiler_block_get_start (block) < loop_start) {
-	g_print ("found jump to before loop, bailing\n");
 	g_list_free (contained);
 	g_list_free (to_check);
 	goto failed;
@@ -717,14 +715,14 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       vivi_decompiler_block_set_branch (start, NULL, NULL);
       loop_start = vivi_decompiler_block_get_start (
 	  vivi_decompiler_block_get_next (start));
-      vivi_code_block_prepend_statement (VIVI_CODE_BLOCK (start), VIVI_CODE_STATEMENT (loop));
+      vivi_code_block_add_statement (VIVI_CODE_BLOCK (start), VIVI_CODE_STATEMENT (loop));
       vivi_decompiler_block_set_next (start, end);
     } else {
       /* FIXME: for (;;) loop */
       contained = g_list_prepend (contained, start);
       block = vivi_decompiler_block_new (vivi_decompiler_state_copy (
 	    vivi_decompiler_block_get_start_state (start)));
-      vivi_code_block_prepend_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (loop));
+      vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (loop));
       for (walk2 = *list; walk2; walk2 = walk2->next) {
 	if (walk2->data == start) {
 	  walk2->data = block;
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index c7f0178..b9bf0d5 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -68,8 +68,14 @@ vivi_decompiler_block_init (ViviDecompilerBlock *block)
 void
 vivi_decompiler_block_reset (ViviDecompilerBlock *block)
 {
-  g_queue_foreach (VIVI_CODE_BLOCK (block)->statements, (GFunc) g_object_unref, NULL);
-  g_queue_clear (VIVI_CODE_BLOCK (block)->statements);
+  ViviCodeBlock *code_block = VIVI_CODE_BLOCK (block);
+  guint i, len;
+  
+  len = vivi_code_block_get_n_statements (code_block);
+  for (i = len - 1; i < len; i--) {
+    vivi_code_block_remove_statement (code_block,
+	vivi_code_block_get_statement (code_block, i));
+  }
   vivi_decompiler_block_set_next (block, NULL);
   vivi_decompiler_block_set_branch (block, NULL, NULL);
   block->endpc = NULL;
@@ -89,24 +95,26 @@ vivi_decompiler_block_new (ViviDecompilerState *state)
   return block;
 }
 
-ViviCodeToken *
+ViviCodeStatement *
 vivi_decompiler_block_get_label (ViviDecompilerBlock *block)
 {
-  ViviCodeToken *token;
+  ViviCodeStatement *stmt;
 
   g_return_val_if_fail (VIVI_IS_DECOMPILER_BLOCK (block), NULL);
 
-  token = g_queue_peek_head (VIVI_CODE_BLOCK (block)->statements);
-  if (!VIVI_IS_CODE_LABEL (token))
+  if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (block)) == 0)
+    return NULL;
+  stmt = vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), 0);
+  if (!VIVI_IS_CODE_LABEL (stmt))
     return NULL;
 
-  return token;
+  return stmt;
 }
 
 void
 vivi_decompiler_block_force_label (ViviDecompilerBlock *block)
 {
-  ViviCodeToken *token;
+  ViviCodeStatement *stmt;
   char *s;
 
   g_return_if_fail (VIVI_IS_DECOMPILER_BLOCK (block));
@@ -115,9 +123,9 @@ vivi_decompiler_block_force_label (ViviDecompilerBlock *block)
     return;
 
   s = g_strdup_printf ("label_%p", block);
-  token = vivi_code_label_new (s);
+  stmt = vivi_code_label_new (s);
   g_free (s);
-  g_queue_push_head (VIVI_CODE_BLOCK (block)->statements, token);
+  vivi_code_block_insert_statement (VIVI_CODE_BLOCK (block), 0, stmt);
 }
 
 void
@@ -223,14 +231,14 @@ void
 vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
     ViviCodeBlock *target)
 {
-  GList *walk;
+  guint i;
 
   g_return_if_fail (VIVI_IS_DECOMPILER_BLOCK (block));
   g_return_if_fail (VIVI_IS_CODE_BLOCK (target));
 
-  for (walk = g_queue_peek_head_link (VIVI_CODE_BLOCK (block)->statements); 
-      walk; walk = walk->next) {
-    vivi_code_block_add_statement (target, g_object_ref (walk->data));
+  for (i = 0; i < vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (block)); i++) {
+    vivi_code_block_add_statement (target, 
+	vivi_code_block_get_statement (VIVI_CODE_BLOCK (block), i));
   }
   if (block->branch) {
     ViviCodeToken *token = vivi_code_if_new (
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
index bac0dfe..a20d0c1 100644
--- a/vivified/code/vivi_decompiler_block.h
+++ b/vivified/code/vivi_decompiler_block.h
@@ -60,7 +60,7 @@ GType			vivi_decompiler_block_get_type   	(void);
 ViviDecompilerBlock *	vivi_decompiler_block_new		(ViviDecompilerState *		state);
 void			vivi_decompiler_block_reset		(ViviDecompilerBlock *		block);
 
-ViviCodeToken *		vivi_decompiler_block_get_label		(ViviDecompilerBlock *  	block);
+ViviCodeStatement *	vivi_decompiler_block_get_label		(ViviDecompilerBlock *  	block);
 void			vivi_decompiler_block_force_label	(ViviDecompilerBlock *		block);
 const ViviDecompilerState *
 			vivi_decompiler_block_get_start_state	(ViviDecompilerBlock *	        block);
commit e33eb7bb32ce183981aaecd5865a778b2bd5c1f6
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 21 13:23:50 2008 +0100

    fix for (;;) loop to not assert anymore

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 5816dea..90ea281 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -717,16 +717,27 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       vivi_decompiler_block_set_branch (start, NULL, NULL);
       loop_start = vivi_decompiler_block_get_start (
 	  vivi_decompiler_block_get_next (start));
+      vivi_code_block_prepend_statement (VIVI_CODE_BLOCK (start), VIVI_CODE_STATEMENT (loop));
+      vivi_decompiler_block_set_next (start, end);
     } else {
       /* FIXME: for (;;) loop */
-      g_assert_not_reached ();
-#if 0
       contained = g_list_prepend (contained, start);
-      start = vivi_decompiler_block_new (vivi_decompiler_state_copy (
+      block = vivi_decompiler_block_new (vivi_decompiler_state_copy (
 	    vivi_decompiler_block_get_start_state (start)));
-#endif
+      vivi_code_block_prepend_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (loop));
+      for (walk2 = *list; walk2; walk2 = walk2->next) {
+	if (walk2->data == start) {
+	  walk2->data = block;
+	  continue;
+	}
+	if (vivi_decompiler_block_get_branch (walk2->data) == start)
+	  vivi_decompiler_block_set_branch (walk2->data, block,
+	      g_object_ref (vivi_decompiler_block_get_branch_condition (walk2->data)));
+	if (vivi_decompiler_block_get_next (walk2->data) == start)
+	  vivi_decompiler_block_set_next (walk2->data, block);
+      }
+      vivi_decompiler_block_set_next (block, end);
     }
-    vivi_decompiler_block_set_next (start, end);
 
     /* break all connections to the outside */
     for (walk2 = contained; walk2; walk2 = walk2->next) {
@@ -735,7 +746,7 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
       next = vivi_decompiler_block_get_branch (block);
       if (next && !g_list_find (contained, next)) {
 	ViviCodeStatement *stmt = VIVI_CODE_STATEMENT (vivi_code_if_new (
-	    vivi_decompiler_block_get_branch_condition (block)));
+	    g_object_ref (vivi_decompiler_block_get_branch_condition (block))));
 	if (next == start) {
 	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_continue_new ());
 	} else if (next == end) {
@@ -764,10 +775,11 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
     }
     /* break all connections from the outside */
     for (walk2 = *list; walk2; walk2 = walk2->next) {
+      block = walk2->data;
       next = vivi_decompiler_block_get_branch (block);
       if (next && !g_list_find (*list, next)) {
 	ViviCodeStatement *stmt = VIVI_CODE_STATEMENT (vivi_code_if_new (
-	    vivi_decompiler_block_get_branch_condition (block)));
+	    g_object_ref (vivi_decompiler_block_get_branch_condition (block))));
 	vivi_decompiler_block_force_label (next);
 	vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (vivi_code_goto_new (
 	      VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
@@ -784,7 +796,6 @@ vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
     }
     vivi_code_loop_set_statement (VIVI_CODE_LOOP (loop), vivi_decompiler_merge_blocks (dec, loop_start,
 	  contained));
-    vivi_code_block_prepend_statement (VIVI_CODE_BLOCK (start), VIVI_CODE_STATEMENT (loop));
 
     return TRUE;
 failed:
commit f8aa9a2cf53f89f53bda06b2a5355b5d0dd6f4cd
Author: Benjamin Otte <otte at gnome.org>
Date:   Thu Mar 20 18:40:52 2008 +0100

    first shot at implementing loops

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index c83bd0f..15fabaa 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -7,12 +7,15 @@ libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
 
 libvivified_compiler_la_SOURCES = \
 	vivi_code_block.c \
+	vivi_code_break.c \
 	vivi_code_comment.c \
 	vivi_code_constant.c \
+	vivi_code_continue.c \
 	vivi_code_get_url.c \
 	vivi_code_goto.c \
 	vivi_code_if.c \
 	vivi_code_label.c \
+	vivi_code_loop.c \
 	vivi_code_printer.c \
 	vivi_code_return.c \
 	vivi_code_statement.c \
@@ -28,12 +31,15 @@ libvivified_compiler_la_SOURCES = \
 
 noinst_HEADERS = \
 	vivi_code_block.h \
+	vivi_code_break.h \
 	vivi_code_comment.h \
 	vivi_code_constant.h \
+	vivi_code_continue.h \
 	vivi_code_get_url.h \
 	vivi_code_goto.h \
 	vivi_code_if.h \
 	vivi_code_label.h \
+	vivi_code_loop.h \
 	vivi_code_printer.h \
 	vivi_code_return.h \
 	vivi_code_statement.h \
diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index 4e15954..52dd476 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -115,6 +115,15 @@ vivi_code_block_new (void)
 }
 
 void
+vivi_code_block_prepend_statement (ViviCodeBlock *block,
+    ViviCodeStatement *statement)
+{
+  g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+
+  g_queue_push_head (block->statements, statement);
+}
+void
 vivi_code_block_add_statement (ViviCodeBlock *block,
     ViviCodeStatement *statement)
 {
@@ -124,3 +133,11 @@ vivi_code_block_add_statement (ViviCodeBlock *block,
   g_queue_push_tail (block->statements, statement);
 }
 
+guint
+vivi_code_block_get_n_statements (ViviCodeBlock *block)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_BLOCK (block), 0);
+
+  return g_queue_get_length (block->statements);
+}
+
diff --git a/vivified/code/vivi_code_block.h b/vivified/code/vivi_code_block.h
index 53b6d3e..b5ce572 100644
--- a/vivified/code/vivi_code_block.h
+++ b/vivified/code/vivi_code_block.h
@@ -51,8 +51,11 @@ GType			vivi_code_block_get_type		(void);
 
 ViviCodeBlock *		vivi_code_block_new			(void);
 
-void			vivi_code_block_add_statement   	(ViviCodeBlock *		block,
-								 ViviCodeStatement *		statement);
+void			vivi_code_block_prepend_statement   	(ViviCodeBlock *	block,
+								 ViviCodeStatement *	statement);
+void			vivi_code_block_add_statement   	(ViviCodeBlock *	block,
+								 ViviCodeStatement *	statement);
+guint			vivi_code_block_get_n_statements	(ViviCodeBlock *	block);
 
 
 G_END_DECLS
diff --git a/vivified/code/vivi_code_break.c b/vivified/code/vivi_code_break.c
new file mode 100644
index 0000000..79e8b6c
--- /dev/null
+++ b/vivified/code/vivi_code_break.c
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_break.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeBreak, vivi_code_break, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_break_print (ViviCodeToken *token, ViviCodePrinter *printer)
+{
+  vivi_code_printer_print (printer, "break;");
+  vivi_code_printer_new_line (printer, FALSE);
+}
+
+static void
+vivi_code_break_class_init (ViviCodeBreakClass *klass)
+{
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  token_class->print = vivi_code_break_print;
+}
+
+static void
+vivi_code_break_init (ViviCodeBreak *token)
+{
+}
+
+ViviCodeStatement *
+vivi_code_break_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_BREAK, NULL);
+}
+
diff --git a/vivified/code/vivi_code_break.h b/vivified/code/vivi_code_break.h
new file mode 100644
index 0000000..c702cc3
--- /dev/null
+++ b/vivified/code/vivi_code_break.h
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_BREAK_H_
+#define _VIVI_CODE_BREAK_H_
+
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeBreak ViviCodeBreak;
+typedef struct _ViviCodeBreakClass ViviCodeBreakClass;
+
+#define VIVI_TYPE_CODE_BREAK                    (vivi_code_break_get_type())
+#define VIVI_IS_CODE_BREAK(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_BREAK))
+#define VIVI_IS_CODE_BREAK_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_BREAK))
+#define VIVI_CODE_BREAK(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_BREAK, ViviCodeBreak))
+#define VIVI_CODE_BREAK_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_BREAK, ViviCodeBreakClass))
+#define VIVI_CODE_BREAK_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_BREAK, ViviCodeBreakClass))
+
+struct _ViviCodeBreak
+{
+  ViviCodeStatement	statement;
+};
+
+struct _ViviCodeBreakClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_break_get_type   	(void);
+
+ViviCodeStatement *	vivi_code_break_new		(void);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_continue.c b/vivified/code/vivi_code_continue.c
new file mode 100644
index 0000000..9464836
--- /dev/null
+++ b/vivified/code/vivi_code_continue.c
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_continue.h"
+#include "vivi_code_printer.h"
+
+G_DEFINE_TYPE (ViviCodeContinue, vivi_code_continue, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_continue_print (ViviCodeToken *token, ViviCodePrinter *printer)
+{
+  vivi_code_printer_print (printer, "continue;");
+  vivi_code_printer_new_line (printer, FALSE);
+}
+
+static void
+vivi_code_continue_class_init (ViviCodeContinueClass *klass)
+{
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  token_class->print = vivi_code_continue_print;
+}
+
+static void
+vivi_code_continue_init (ViviCodeContinue *token)
+{
+}
+
+ViviCodeStatement *
+vivi_code_continue_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_CONTINUE, NULL);
+}
+
diff --git a/vivified/code/vivi_code_continue.h b/vivified/code/vivi_code_continue.h
new file mode 100644
index 0000000..540e1eb
--- /dev/null
+++ b/vivified/code/vivi_code_continue.h
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_CONTINUE_H_
+#define _VIVI_CODE_CONTINUE_H_
+
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeContinue ViviCodeContinue;
+typedef struct _ViviCodeContinueClass ViviCodeContinueClass;
+
+#define VIVI_TYPE_CODE_CONTINUE                    (vivi_code_continue_get_type())
+#define VIVI_IS_CODE_CONTINUE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_CONTINUE))
+#define VIVI_IS_CODE_CONTINUE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_CONTINUE))
+#define VIVI_CODE_CONTINUE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_CONTINUE, ViviCodeContinue))
+#define VIVI_CODE_CONTINUE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_CONTINUE, ViviCodeContinueClass))
+#define VIVI_CODE_CONTINUE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_CONTINUE, ViviCodeContinueClass))
+
+struct _ViviCodeContinue
+{
+  ViviCodeStatement	statement;
+};
+
+struct _ViviCodeContinueClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_continue_get_type   	(void);
+
+ViviCodeStatement *	vivi_code_continue_new		(void);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_loop.c b/vivified/code/vivi_code_loop.c
new file mode 100644
index 0000000..78c9048
--- /dev/null
+++ b/vivified/code/vivi_code_loop.c
@@ -0,0 +1,116 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_loop.h"
+#include "vivi_code_printer.h"
+#include "vivi_code_unary.h"
+
+G_DEFINE_TYPE (ViviCodeLoop, vivi_code_loop, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_loop_dispose (GObject *object)
+{
+  ViviCodeLoop *loop = VIVI_CODE_LOOP (object);
+
+  if (loop->condition)
+    g_object_unref (loop->condition);
+  if (loop->statement)
+    g_object_unref (loop->statement);
+
+  G_OBJECT_CLASS (vivi_code_loop_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_loop_print (ViviCodeToken *token, ViviCodePrinter *printer)
+{
+  ViviCodeLoop *loop= VIVI_CODE_LOOP (token);
+  gboolean needs_braces;
+
+  needs_braces = loop->statement && vivi_code_statement_needs_braces (loop->statement);
+  if (loop->condition) {
+    vivi_code_printer_print (printer, "while (");
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (loop->condition));
+    vivi_code_printer_print (printer, ")");
+  } else {
+    vivi_code_printer_print (printer, "for (;;)");
+  }
+  if (needs_braces)
+    vivi_code_printer_print (printer, " {");
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_push_indentation (printer);
+  if (loop->statement) {
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (loop->statement));
+  } else {
+    vivi_code_printer_print (printer, ";");
+  }
+  vivi_code_printer_pop_indentation (printer);
+  if (needs_braces) {
+    vivi_code_printer_print (printer, "}");
+    vivi_code_printer_new_line (printer, FALSE);
+  }
+}
+
+static void
+vivi_code_loop_class_init (ViviCodeLoopClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_loop_dispose;
+
+  token_class->print = vivi_code_loop_print;
+}
+
+static void
+vivi_code_loop_init (ViviCodeLoop *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_loop_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_LOOP, NULL);
+}
+
+void
+vivi_code_loop_set_condition (ViviCodeLoop *loop, ViviCodeValue *condition)
+{
+  g_return_if_fail (VIVI_IS_CODE_LOOP (loop));
+  g_return_if_fail (VIVI_IS_CODE_VALUE (condition));
+
+  if (loop->condition)
+    g_object_unref (loop->condition);
+  loop->condition = condition;
+}
+
+void
+vivi_code_loop_set_statement (ViviCodeLoop *loop, ViviCodeStatement *statement)
+{
+  g_return_if_fail (VIVI_IS_CODE_LOOP (loop));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+
+  if (loop->statement)
+    g_object_unref (loop->statement);
+  loop->statement = statement;
+}
+
diff --git a/vivified/code/vivi_code_loop.h b/vivified/code/vivi_code_loop.h
new file mode 100644
index 0000000..d8742a9
--- /dev/null
+++ b/vivified/code/vivi_code_loop.h
@@ -0,0 +1,62 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_LOOP_H_
+#define _VIVI_CODE_LOOP_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeLoop ViviCodeLoop;
+typedef struct _ViviCodeLoopClass ViviCodeLoopClass;
+
+#define VIVI_TYPE_CODE_LOOP                    (vivi_code_loop_get_type())
+#define VIVI_IS_CODE_LOOP(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_LOOP))
+#define VIVI_IS_CODE_LOOP_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_LOOP))
+#define VIVI_CODE_LOOP(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_LOOP, ViviCodeLoop))
+#define VIVI_CODE_LOOP_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_LOOP, ViviCodeLoopClass))
+#define VIVI_CODE_LOOP_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_LOOP, ViviCodeLoopClass))
+
+struct _ViviCodeLoop
+{
+  ViviCodeStatement	parent;
+
+  ViviCodeValue *	condition;
+  ViviCodeStatement *	statement;
+};
+
+struct _ViviCodeLoopClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_loop_get_type   	(void);
+
+ViviCodeToken *		vivi_code_loop_new		(void);
+void			vivi_code_loop_set_condition	(ViviCodeLoop *		loop,
+							 ViviCodeValue *	condition);
+void			vivi_code_loop_set_statement	(ViviCodeLoop *		loop,
+							 ViviCodeStatement *	statement);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
index 60fb26e..5c9414b 100644
--- a/vivified/code/vivi_code_unary.c
+++ b/vivified/code/vivi_code_unary.c
@@ -95,7 +95,7 @@ vivi_code_unary_init (ViviCodeUnary *unary)
   vivi_code_value_set_precedence (value, VIVI_PRECEDENCE_UNARY);
 }
 
-ViviCodeToken *
+ViviCodeValue *
 vivi_code_unary_new (ViviCodeValue *value, char operation)
 {
   ViviCodeUnary *unary;
@@ -106,6 +106,6 @@ vivi_code_unary_new (ViviCodeValue *value, char operation)
   unary->value = value;
   unary->operation = operation;
 
-  return VIVI_CODE_TOKEN (unary);
+  return VIVI_CODE_VALUE (unary);
 }
 
diff --git a/vivified/code/vivi_code_unary.h b/vivified/code/vivi_code_unary.h
index 45e060e..23f93c0 100644
--- a/vivified/code/vivi_code_unary.h
+++ b/vivified/code/vivi_code_unary.h
@@ -50,7 +50,7 @@ struct _ViviCodeUnaryClass
 
 GType			vivi_code_unary_get_type   	(void);
 
-ViviCodeToken *		vivi_code_unary_new		(ViviCodeValue *	value,
+ViviCodeValue *		vivi_code_unary_new		(ViviCodeValue *	value,
 							 char			operation);
 
 char			vivi_code_unary_get_operation	(ViviCodeUnary *	unary);
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 0354aec..5816dea 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -28,9 +28,14 @@
 #include <swfdec/swfdec_script_internal.h>
 
 #include "vivi_decompiler.h"
+#include "vivi_code_block.h"
+#include "vivi_code_break.h"
 #include "vivi_code_constant.h"
+#include "vivi_code_continue.h"
 #include "vivi_code_get_url.h"
+#include "vivi_code_goto.h"
 #include "vivi_code_if.h"
+#include "vivi_code_loop.h"
 #include "vivi_code_return.h"
 #include "vivi_code_trace.h"
 #include "vivi_code_unary.h"
@@ -271,7 +276,7 @@ vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
   ViviCodeValue *val;
 
   val = vivi_decompiler_state_pop (state);
-  val = VIVI_CODE_VALUE (vivi_code_unary_new (val, '!'));
+  val = vivi_code_unary_new (val, '!');
   vivi_decompiler_state_push (state, val);
   return TRUE;
 }
@@ -423,28 +428,28 @@ error:
 /*** PROGRAM STRUCTURE ANALYSIS ***/
 
 static ViviDecompilerBlock *
-vivi_decompiler_find_start_block (ViviDecompiler *dec)
+vivi_decompiler_find_start_block (GList *list, const guint8 *startpc)
 {
   GList *walk;
   
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = list; walk; walk = walk->next) {
     ViviDecompilerBlock *block = walk->data;
 
-    if (vivi_decompiler_block_get_start (block) == dec->script->main)
+    if (vivi_decompiler_block_get_start (block) == startpc)
       return block;
   }
   g_assert_not_reached ();
   return NULL;
 }
 
-static ViviCodeToken *
-vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec, GList *list)
+static ViviCodeStatement *
+vivi_decompiler_merge_blocks_last_resort (GList *list, const guint8 *startpc)
 {
   ViviCodeBlock *block;
   ViviDecompilerBlock *current, *next;
   GList *ordered, *walk;
 
-  current = vivi_decompiler_find_start_block (dec);
+  current = vivi_decompiler_find_start_block (list, startpc);
 
   ordered = NULL;
   while (current) {
@@ -477,7 +482,7 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec, GList *list)
   }
   g_list_foreach (ordered, (GFunc) g_object_unref, NULL);
   g_list_free (ordered);
-  return VIVI_CODE_TOKEN (block);
+  return VIVI_CODE_STATEMENT (block);
 }
 
 static GList *
@@ -609,8 +614,187 @@ vivi_decompiler_merge_if (ViviDecompiler *dec, GList **list)
   return result;
 }
 
-static ViviCodeToken *
-vivi_decompiler_merge_blocks (ViviDecompiler *dec, GList *blocks)
+static ViviCodeStatement *vivi_decompiler_merge_blocks (ViviDecompiler *dec, 
+    const guint8 *startpc, GList *blocks);
+
+static gboolean
+vivi_decompiler_merge_loops (ViviDecompiler *dec, GList **list)
+{
+  ViviDecompilerBlock *end, *start, *block, *next;
+  gboolean result;
+  GList *walk, *walk2;
+  const guint8 *loop_start, *loop_end;
+  GList *contained, *to_check;
+  ViviCodeToken *loop;
+
+  result = FALSE;
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    end = walk->data;
+    /* noone has a branch at the end of a loop */
+    if (vivi_decompiler_block_get_branch (end))
+      continue;
+    start = vivi_decompiler_block_get_next (end);
+    /* block that just returns - no loop at all */
+    if (start == NULL)
+      continue;
+    /* not a jump backwards, so no loop end */
+    if (vivi_decompiler_block_get_start (start) >
+	vivi_decompiler_block_get_start (end))
+      continue;
+    /* We've found that "end" is a jump backwards. Now, this can be 3 things:
+     * a) the end of a loop
+     *    Woohoo, we've found our loop end.
+     * b) a "continue" statement
+     *    Wait, we need to find where the lop ends!
+     * c) a goto backwards
+     *    Whoops, we need to cleanly exit this loop!
+     * In case a) and b), "start" will already be correct. So we'll assume that
+     * it is and go from there.
+     */
+    loop_start = vivi_decompiler_block_get_start (start);
+    g_print ("found a loop starting at %p\n", loop_start);
+    /* this is just a rough guess for now */
+    loop_end = vivi_decompiler_block_get_start (end);
+    /* let's find the rest of the loop */
+    to_check = g_list_prepend (contained, start);
+    contained = NULL;
+    while (to_check) {
+      block = to_check->data;
+      to_check = g_list_remove (to_check, block);
+      /* jump to before start?! */
+      if (vivi_decompiler_block_get_start (block) < loop_start) {
+	g_print ("found jump to before loop, bailing\n");
+	g_list_free (contained);
+	g_list_free (to_check);
+	goto failed;
+      }
+      /* found a new end of the loop */
+      if (vivi_decompiler_block_get_start (block) > loop_end) {
+	ViviDecompilerBlock *swap;
+	loop_end = vivi_decompiler_block_get_start (block);
+	swap = block;
+	block = end;
+	end = swap;
+      }
+      contained = g_list_prepend (contained, block);
+      next = vivi_decompiler_block_get_next (block);
+      if (next && next != end && 
+	  !g_list_find (contained, next) && 
+          !g_list_find (to_check, next))
+	to_check = g_list_prepend (to_check, next);
+      next = vivi_decompiler_block_get_branch (block);
+      if (next && next != end && 
+	  !g_list_find (contained, next) && 
+          !g_list_find (to_check, next))
+	to_check = g_list_prepend (to_check, next);
+    }
+    contained = g_list_reverse (contained);
+    contained = g_list_remove (contained, start);
+    /* now we have:
+     * contained: contains all the blocks contained in the loop
+     * start: starting block
+     * end: end block - where "breaks" go to
+     */
+    loop = vivi_code_loop_new ();
+    /* check if the first block is just a branch, in that case it's the
+     * loop condition */
+    if (vivi_code_block_get_n_statements (VIVI_CODE_BLOCK (start)) == 0 &&
+	(vivi_decompiler_block_get_branch (start) == end ||
+	 (vivi_decompiler_block_get_branch (start) &&
+	  vivi_decompiler_block_get_next (start) == end))) {
+      if (vivi_decompiler_block_get_branch (start) == end) {
+	ViviCodeValue *value = vivi_code_unary_new (g_object_ref (
+	    vivi_decompiler_block_get_branch_condition (start)), '!');
+	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop),
+	    vivi_code_value_optimize (value, SWFDEC_AS_TYPE_BOOLEAN));
+	g_object_unref (value);
+      } else {
+	vivi_code_loop_set_condition (VIVI_CODE_LOOP (loop), g_object_ref (
+	    vivi_decompiler_block_get_branch_condition (start)));
+	vivi_decompiler_block_set_next (start,
+	    vivi_decompiler_block_get_branch (start));
+      }
+      vivi_decompiler_block_set_branch (start, NULL, NULL);
+      loop_start = vivi_decompiler_block_get_start (
+	  vivi_decompiler_block_get_next (start));
+    } else {
+      /* FIXME: for (;;) loop */
+      g_assert_not_reached ();
+#if 0
+      contained = g_list_prepend (contained, start);
+      start = vivi_decompiler_block_new (vivi_decompiler_state_copy (
+	    vivi_decompiler_block_get_start_state (start)));
+#endif
+    }
+    vivi_decompiler_block_set_next (start, end);
+
+    /* break all connections to the outside */
+    for (walk2 = contained; walk2; walk2 = walk2->next) {
+      block = walk2->data;
+      *list = g_list_remove (*list, block);
+      next = vivi_decompiler_block_get_branch (block);
+      if (next && !g_list_find (contained, next)) {
+	ViviCodeStatement *stmt = VIVI_CODE_STATEMENT (vivi_code_if_new (
+	    vivi_decompiler_block_get_branch_condition (block)));
+	if (next == start) {
+	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_continue_new ());
+	} else if (next == end) {
+	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), vivi_code_break_new ());
+	} else {
+	  vivi_decompiler_block_force_label (next);
+	  vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (vivi_code_goto_new (
+		VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
+	}
+	vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
+	vivi_decompiler_block_set_branch (block, NULL, NULL);
+      }
+      next = vivi_decompiler_block_get_next (block);
+      if (next && !g_list_find (contained, next)) {
+	if (next == start) {
+	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), vivi_code_continue_new ());
+	} else if (next == end) {
+	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), vivi_code_break_new ());
+	} else {
+	  vivi_decompiler_block_force_label (next);
+	  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (
+		vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
+	}
+	vivi_decompiler_block_set_next (block, NULL);
+      }
+    }
+    /* break all connections from the outside */
+    for (walk2 = *list; walk2; walk2 = walk2->next) {
+      next = vivi_decompiler_block_get_branch (block);
+      if (next && !g_list_find (*list, next)) {
+	ViviCodeStatement *stmt = VIVI_CODE_STATEMENT (vivi_code_if_new (
+	    vivi_decompiler_block_get_branch_condition (block)));
+	vivi_decompiler_block_force_label (next);
+	vivi_code_if_set_if (VIVI_CODE_IF (stmt), VIVI_CODE_STATEMENT (vivi_code_goto_new (
+	      VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
+	vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
+	vivi_decompiler_block_set_branch (block, NULL, NULL);
+      }
+      next = vivi_decompiler_block_get_next (block);
+      if (next && !g_list_find (*list, next)) {
+	vivi_decompiler_block_force_label (next);
+	vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (
+	      vivi_code_goto_new (VIVI_CODE_LABEL (vivi_decompiler_block_get_label (next)))));
+	vivi_decompiler_block_set_next (block, NULL);
+      }
+    }
+    vivi_code_loop_set_statement (VIVI_CODE_LOOP (loop), vivi_decompiler_merge_blocks (dec, loop_start,
+	  contained));
+    vivi_code_block_prepend_statement (VIVI_CODE_BLOCK (start), VIVI_CODE_STATEMENT (loop));
+
+    return TRUE;
+failed:
+    continue;
+  }
+  return FALSE;
+}
+
+static ViviCodeStatement *
+vivi_decompiler_merge_blocks (ViviDecompiler *dec, const guint8 *startpc, GList *blocks)
 {
   gboolean restart;
 
@@ -621,10 +805,11 @@ vivi_decompiler_merge_blocks (ViviDecompiler *dec, GList *blocks)
 
     restart |= vivi_decompiler_merge_lines (dec, &blocks);
     restart |= vivi_decompiler_merge_if (dec, &blocks);
+    restart |= vivi_decompiler_merge_loops (dec, &blocks);
   } while (restart);
 
   DUMP_BLOCKS (dec);
-  return vivi_decompiler_merge_blocks_last_resort (dec, blocks);
+  return vivi_decompiler_merge_blocks_last_resort (blocks, startpc);
 }
 
 static void
@@ -665,7 +850,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block;
   ViviDecompilerState *state;
-  ViviCodeToken *token;
+  ViviCodeStatement *stmt;
   GList *walk;
 
   state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
@@ -689,8 +874,8 @@ vivi_decompiler_run (ViviDecompiler *dec)
   }
 
   vivi_decompiler_dump_graphviz (dec);
-  token = vivi_decompiler_merge_blocks (dec, dec->blocks);
-  dec->blocks = g_list_prepend (NULL, token);
+  stmt = vivi_decompiler_merge_blocks (dec, dec->script->main, dec->blocks);
+  dec->blocks = g_list_prepend (NULL, stmt);
 }
 
 /*** OBJECT ***/
commit 79b9267c45689943d4b1dfe36bff16f4e60fc987
Author: Benjamin Otte <otte at gnome.org>
Date:   Thu Mar 20 15:49:11 2008 +0100

    generalize the merging code to work on any list of blocks

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index f465939..0354aec 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -437,8 +437,8 @@ vivi_decompiler_find_start_block (ViviDecompiler *dec)
   return NULL;
 }
 
-static void
-vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
+static ViviCodeToken *
+vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec, GList *list)
 {
   ViviCodeBlock *block;
   ViviDecompilerBlock *current, *next;
@@ -448,21 +448,21 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
 
   ordered = NULL;
   while (current) {
-    g_assert (g_list_find (dec->blocks, current));
-    dec->blocks = g_list_remove (dec->blocks, current);
+    g_assert (g_list_find (list, current));
+    list = g_list_remove (list, current);
     ordered = g_list_prepend (ordered, current);
     next = vivi_decompiler_block_get_branch (current);
     if (next)
       vivi_decompiler_block_force_label (next);
     next = vivi_decompiler_block_get_next (current);
-    if (next == NULL || !g_list_find (dec->blocks, next)) {
+    if (next == NULL || !g_list_find (list, next)) {
       if (next)
 	vivi_decompiler_block_force_label (next);
-      next = dec->blocks ? dec->blocks->data : NULL;
+      next = list ? list->data : NULL;
     }
     current = next;
   }
-  g_assert (dec->blocks == NULL);
+  g_assert (list == NULL);
   ordered = g_list_reverse (ordered);
 
   block = VIVI_CODE_BLOCK (vivi_code_block_new ());
@@ -477,15 +477,16 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
   }
   g_list_foreach (ordered, (GFunc) g_object_unref, NULL);
   g_list_free (ordered);
-  dec->blocks = g_list_prepend (dec->blocks, block);
+  return VIVI_CODE_TOKEN (block);
 }
 
-static void
-vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
+static GList *
+vivi_decompiler_purge_block (GList *list, ViviDecompilerBlock *block)
 {
   g_assert (vivi_decompiler_block_get_n_incoming (block) == 0);
-  dec->blocks = g_list_remove (dec->blocks, block);
+  list = g_list_remove (list, block);
   g_object_unref (block);
+  return list;
 }
 
 /*  ONE
@@ -493,7 +494,7 @@ vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
  *  TWO
  */
 static gboolean
-vivi_decompiler_merge_lines (ViviDecompiler *dec)
+vivi_decompiler_merge_lines (ViviDecompiler *dec, GList **list)
 {
   ViviDecompilerBlock *block, *next;
   ViviCodeValue *val;
@@ -501,7 +502,7 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec)
   GList *walk;
 
   result = FALSE;
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = *list; walk; walk = walk->next) {
     block = walk->data;
 
     /* This is an if block or so */
@@ -525,7 +526,7 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec)
     vivi_decompiler_block_set_next (next, NULL);
     vivi_decompiler_block_set_branch (next, NULL, NULL);
     vivi_decompiler_block_add_to_block (next, VIVI_CODE_BLOCK (block));
-    vivi_decompiler_purge_block (dec, next);
+    *list = vivi_decompiler_purge_block (*list, next);
     result = TRUE;
   }
 
@@ -539,7 +540,7 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec)
  *     NEXT
  */
 static gboolean
-vivi_decompiler_merge_if (ViviDecompiler *dec)
+vivi_decompiler_merge_if (ViviDecompiler *dec, GList **list)
 {
   ViviDecompilerBlock *block, *if_block, *else_block;
   ViviCodeIf *if_stmt;
@@ -548,7 +549,7 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
   GList *walk;
 
   result = FALSE;
-  for (walk = dec->blocks; walk; walk = walk->next) {
+  for (walk = *list; walk; walk = walk->next) {
     block = walk->data;
 
     if_block = vivi_decompiler_block_get_branch (block);
@@ -586,7 +587,7 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       vivi_decompiler_block_set_next (if_block, NULL);
       vivi_decompiler_block_set_branch (if_block, NULL, NULL);
       vivi_decompiler_block_add_to_block (if_block, tmp);
-      vivi_decompiler_purge_block (dec, if_block);
+      *list = vivi_decompiler_purge_block (*list, if_block);
       vivi_code_if_set_if (if_stmt, VIVI_CODE_STATEMENT (tmp));
     }
     if (else_block) {
@@ -595,7 +596,7 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       vivi_decompiler_block_set_next (else_block, NULL);
       vivi_decompiler_block_set_branch (else_block, NULL, NULL);
       vivi_decompiler_block_add_to_block (else_block, tmp);
-      vivi_decompiler_purge_block (dec, else_block);
+      *list = vivi_decompiler_purge_block (*list, else_block);
       vivi_code_if_set_else (if_stmt, VIVI_CODE_STATEMENT (tmp));
     }
     stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (if_stmt));
@@ -608,8 +609,8 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
   return result;
 }
 
-static void
-vivi_decompiler_merge_blocks (ViviDecompiler *dec)
+static ViviCodeToken *
+vivi_decompiler_merge_blocks (ViviDecompiler *dec, GList *blocks)
 {
   gboolean restart;
 
@@ -618,12 +619,12 @@ vivi_decompiler_merge_blocks (ViviDecompiler *dec)
   do {
     restart = FALSE;
 
-    restart |= vivi_decompiler_merge_lines (dec);
-    restart |= vivi_decompiler_merge_if (dec);
+    restart |= vivi_decompiler_merge_lines (dec, &blocks);
+    restart |= vivi_decompiler_merge_if (dec, &blocks);
   } while (restart);
 
   DUMP_BLOCKS (dec);
-  vivi_decompiler_merge_blocks_last_resort (dec);
+  return vivi_decompiler_merge_blocks_last_resort (dec, blocks);
 }
 
 static void
@@ -664,6 +665,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block;
   ViviDecompilerState *state;
+  ViviCodeToken *token;
   GList *walk;
 
   state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
@@ -687,7 +689,8 @@ vivi_decompiler_run (ViviDecompiler *dec)
   }
 
   vivi_decompiler_dump_graphviz (dec);
-  vivi_decompiler_merge_blocks (dec);
+  token = vivi_decompiler_merge_blocks (dec, dec->blocks);
+  dec->blocks = g_list_prepend (NULL, token);
 }
 
 /*** OBJECT ***/
commit b805a305b4c45fc9f1c61fd970d36cef3e2875f8
Author: Benjamin Otte <otte at gnome.org>
Date:   Thu Mar 20 10:16:44 2008 +0100

    fix for ming API updates

diff --git a/vivified/core/vivi_ming.c b/vivified/core/vivi_ming.c
index a126455..c015c1a 100644
--- a/vivified/core/vivi_ming.c
+++ b/vivified/core/vivi_ming.c
@@ -88,7 +88,7 @@ vivi_ming_compile (const char *code, char **error)
 {
   byte *data;
   SWFAction action;
-  gsize len;
+  gssize len;
   SwfdecBuffer *buffer;
   SwfdecScript *script;
 
commit 66d814793f340ea53f2f41d3122140455f68be71
Merge: 12dff40... 2577ca9...
Author: Benjamin Otte <otte at gnome.org>
Date:   Thu Mar 20 10:13:02 2008 +0100

    Merge branch 'master' into decompiler

commit 12dff4041964411cfb1810524c4167c964d7db95
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 19:57:10 2008 +0100

    continue parsing on errors

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 52f9edd..f465939 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -136,7 +136,7 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 	  char *s = swfdec_bits_get_string (&bits, vivi_decompiler_state_get_version (state));
 	  if (s == NULL) {
 	    vivi_decompiler_block_add_error (block, "could not read string");
-	    return FALSE;
+	    return TRUE;
 	  }
 	  value = escape_string (s);
 	  g_free (s);
@@ -173,19 +173,19 @@ vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
 	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
 	  if (pool == NULL) {
 	    vivi_decompiler_block_add_error (block, "no constant pool to push from");
-	    return FALSE;
+	    return TRUE;
 	  }
 	  if (i >= swfdec_constant_pool_size (pool)) {
 	    vivi_decompiler_block_add_error (block, "constant pool index %u too high - only %u elements",
 		i, swfdec_constant_pool_size (pool));
-	    return FALSE;
+	    return TRUE;
 	  }
 	  value = escape_string (swfdec_constant_pool_get (pool, i));
 	  break;
 	}
       default:
 	vivi_decompiler_block_add_error (block, "Push: type %u not implemented", type);
-	return FALSE;
+	return TRUE;
     }
     val = VIVI_CODE_VALUE (vivi_code_constant_new (value));
     vivi_decompiler_state_push (state, val);
@@ -303,12 +303,13 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	ViviDecompilerState *new;
 	gint16 offset;
 
+	vivi_decompiler_state_add_pc (state, 5);
 	if (len != 2) {
 	  vivi_decompiler_block_add_error (block, "If action length invalid (is %u, should be 2)", len);
-	  return FALSE;
+	  vivi_decompiler_block_finish (block, state);
+	  return TRUE;
 	}
 	offset = data[0] | (data[1] << 8);
-	vivi_decompiler_state_add_pc (state, 5);
 	val = vivi_decompiler_state_pop (state);
 	vivi_decompiler_block_finish (block, state);
 	new = vivi_decompiler_state_copy (state);
@@ -330,12 +331,13 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	ViviDecompilerState *new;
 	gint16 offset;
 
+	vivi_decompiler_state_add_pc (state, 5);
 	if (len != 2) {
 	  vivi_decompiler_block_add_error (block, "Jump action length invalid (is %u, should be 2)", len);
+	  vivi_decompiler_block_finish (block, state);
 	  return FALSE;
 	}
 	offset = data[0] | (data[1] << 8);
-	vivi_decompiler_state_add_pc (state, 5);
 	vivi_decompiler_block_finish (block, state);
 	new = vivi_decompiler_state_copy (state);
 	vivi_decompiler_state_add_pc (new, offset);
@@ -350,7 +352,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	result = decompile_funcs[code] (block, state, code, data, len);
       } else {
 	vivi_decompiler_block_add_error (block, "unknown bytecode 0x%02X %u", code, code);
-	result = FALSE;
+	result = TRUE;
       }
       if (data)
 	vivi_decompiler_state_add_pc (state, 3 + len);
commit 8c82bdbd72f64e507ae810922281306720799bde
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 19:43:36 2008 +0100

    add rough code to dump internal state to graphviz
    
    The code dumps before starting to do any optimizations in the program flow.
    To get the dump, you need to define the env var VIVI_DECOMPILER_DUMP to the
    name of the file to dump to.

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 58a0bd4..52f9edd 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -625,6 +625,39 @@ vivi_decompiler_merge_blocks (ViviDecompiler *dec)
 }
 
 static void
+vivi_decompiler_dump_graphviz (ViviDecompiler *dec)
+{
+  GString *string;
+  GList *walk;
+  const char *filename;
+
+  filename = g_getenv ("VIVI_DECOMPILER_DUMP");
+  if (filename == NULL)
+    return;
+
+  string = g_string_new ("digraph G\n{\n");
+  g_string_append (string, "  node [ shape = box ]\n");
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    g_string_append_printf (string, "  node%p\n", walk->data);
+  }
+  g_string_append (string, "\n");
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    ViviDecompilerBlock *block, *next;
+
+    block = walk->data;
+    next = vivi_decompiler_block_get_next (block);
+    if (next)
+      g_string_append_printf (string, "  node%p -> node%p\n", block, next);
+    next = vivi_decompiler_block_get_branch (block);
+    if (next)
+      g_string_append_printf (string, "  node%p -> node%p\n", block, next);
+  }
+  g_string_append (string, "}\n");
+  g_file_set_contents (filename, string->str, string->len, NULL);
+  g_string_free (string, TRUE);
+}
+
+static void
 vivi_decompiler_run (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block;
@@ -651,6 +684,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
     vivi_decompiler_block_decompile (dec, block);
   }
 
+  vivi_decompiler_dump_graphviz (dec);
   vivi_decompiler_merge_blocks (dec);
 }
 
commit 6b505c9ddad55abc64f75cb49b469494f37722aa
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 19:11:48 2008 +0100

    we now have better brace matching, so fi tests

diff --git a/vivified/code/test/if-nested.swf.expect b/vivified/code/test/if-nested.swf.expect
index 62e7138..828337a 100644
--- a/vivified/code/test/if-nested.swf.expect
+++ b/vivified/code/test/if-nested.swf.expect
@@ -2,15 +2,12 @@
 
 /* Sprite0_Frame0 */
 {
-  if (1)
-  {
+  if (1) {
     if (2)
       trace ("one");
     else
       trace ("two");
-  }
-  else
-  {
+  } else {
     if (3)
       trace ("three");
     else
commit b789bd00f89bef089985d5d90919631119d3497d
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 19:11:01 2008 +0100

    make braces be handled by parents, not by blocks themselves
    
    Improves braces handling by If statements

diff --git a/vivified/code/decompiler.c b/vivified/code/decompiler.c
index 1626172..3449cb3 100644
--- a/vivified/code/decompiler.c
+++ b/vivified/code/decompiler.c
@@ -42,8 +42,11 @@ decode_script (gpointer offset, gpointer scriptp, gpointer unused)
   g_print ("/* %s */\n", script->name);
   token = VIVI_CODE_TOKEN (vivi_decompiler_get_block (dec));
   printer = vivi_code_text_printer_new ();
+  g_print ("{\n");
+  vivi_code_printer_push_indentation (printer);
   vivi_code_printer_print_token (printer, token);
-  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_pop_indentation (printer);
+  g_print ("}\n\n");
   g_object_unref (printer);
   g_object_unref (dec);
 }
diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index d0978d1..4e15954 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -59,25 +59,25 @@ static gboolean
 vivi_code_block_needs_braces (ViviCodeStatement *stmt)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (stmt);
+  GList *first;
 
-  return g_queue_get_length (block->statements) > 1;
+  first = g_queue_peek_head_link (block->statements);
+
+  if (first == NULL)
+    return FALSE;
+  if (first->next)
+    return TRUE;
+  return vivi_code_statement_needs_braces (first->data);
 }
 
 static void
 vivi_code_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (token);
-  guint length;
 
-  length = g_queue_get_length (block->statements);
-  if (length > 1) {
-    vivi_code_printer_new_line (printer, FALSE);
-    vivi_code_printer_print (printer, "{");
-  }
-  vivi_code_printer_push_indentation (printer);
-  if (length == 0) {
-    vivi_code_printer_new_line (printer, FALSE);
+  if (g_queue_is_empty (block->statements)) {
     vivi_code_printer_print (printer, ";");
+    vivi_code_printer_new_line (printer, FALSE);
   } else {
     GList *walk;
 
@@ -85,11 +85,6 @@ vivi_code_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
       vivi_code_printer_print_token (printer, walk->data);
     }
   }
-  vivi_code_printer_pop_indentation (printer);
-  if (length > 1) {
-    vivi_code_printer_new_line (printer, FALSE);
-    vivi_code_printer_print (printer, "}");
-  }
 }
 
 static void
diff --git a/vivified/code/vivi_code_comment.c b/vivified/code/vivi_code_comment.c
index 31bce87..83cdfd8 100644
--- a/vivified/code/vivi_code_comment.c
+++ b/vivified/code/vivi_code_comment.c
@@ -41,10 +41,10 @@ vivi_code_comment_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeComment *comment = VIVI_CODE_COMMENT (token);
 
-  vivi_code_printer_new_line (printer, FALSE);
   vivi_code_printer_print (printer, "/* ");
   vivi_code_printer_print (printer, comment->comment);
   vivi_code_printer_print (printer, " */");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
diff --git a/vivified/code/vivi_code_get_url.c b/vivified/code/vivi_code_get_url.c
index 1fcc676..1fdaddc 100644
--- a/vivified/code/vivi_code_get_url.c
+++ b/vivified/code/vivi_code_get_url.c
@@ -42,8 +42,6 @@ vivi_code_get_url_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeGetUrl *url = VIVI_CODE_GET_URL (token);
 
-  vivi_code_printer_new_line (printer, FALSE);
-
   if (url->variables) {
     vivi_code_printer_print (printer, "loadVariables (");
   } else if (url->internal) {
@@ -59,6 +57,7 @@ vivi_code_get_url_print (ViviCodeToken *token, ViviCodePrinter *printer)
 	url->method == 2 ? ", \"POST\"" : ", \"GET\"");
   }
   vivi_code_printer_print (printer, ");");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
diff --git a/vivified/code/vivi_code_goto.c b/vivified/code/vivi_code_goto.c
index 4f33be4..44e7f32 100644
--- a/vivified/code/vivi_code_goto.c
+++ b/vivified/code/vivi_code_goto.c
@@ -41,10 +41,10 @@ vivi_code_goto_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeGoto *gotoo = VIVI_CODE_GOTO (token);
 
-  vivi_code_printer_new_line (printer, FALSE);
   vivi_code_printer_print (printer, "goto ");
   vivi_code_printer_print (printer, vivi_code_label_get_name (gotoo->label));
   vivi_code_printer_print (printer, ";");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index b2b9a54..b289ded 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -84,13 +84,20 @@ static void
 vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeIf *stmt = VIVI_CODE_IF (token);
+  gboolean needs_braces;
 
-  vivi_code_printer_new_line (printer, FALSE);
   vivi_code_printer_print (printer, "if (");
   vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->condition));
   vivi_code_printer_print (printer, ")");
+  needs_braces = stmt->if_statement && vivi_code_statement_needs_braces (stmt->if_statement);
+  needs_braces |= stmt->else_statement && vivi_code_statement_needs_braces (stmt->else_statement);
   if (stmt->if_statement) {
+    if (needs_braces)
+      vivi_code_printer_print (printer, " {");
+    vivi_code_printer_new_line (printer, FALSE);
+    vivi_code_printer_push_indentation (printer);
     vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->if_statement));
+    vivi_code_printer_pop_indentation (printer);
   } else {
     vivi_code_printer_push_indentation (printer);
     vivi_code_printer_new_line (printer, FALSE);
@@ -98,9 +105,18 @@ vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
     vivi_code_printer_pop_indentation (printer);
   }
   if (stmt->else_statement) {
+    if (needs_braces)
+      vivi_code_printer_print (printer, "} else {");
+    else
+      vivi_code_printer_print (printer, "else");
     vivi_code_printer_new_line (printer, FALSE);
-    vivi_code_printer_print (printer, "else");
+    vivi_code_printer_push_indentation (printer);
     vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->else_statement));
+    vivi_code_printer_pop_indentation (printer);
+  }
+  if (needs_braces) {
+    vivi_code_printer_print (printer, "}");
+    vivi_code_printer_new_line (printer, FALSE);
   }
 }
 
diff --git a/vivified/code/vivi_code_label.c b/vivified/code/vivi_code_label.c
index 85a0ce5..6813f2d 100644
--- a/vivified/code/vivi_code_label.c
+++ b/vivified/code/vivi_code_label.c
@@ -44,6 +44,7 @@ vivi_code_label_print (ViviCodeToken *token, ViviCodePrinter *printer)
   vivi_code_printer_new_line (printer, TRUE);
   vivi_code_printer_print (printer, label->name);
   vivi_code_printer_print (printer, ":");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
diff --git a/vivified/code/vivi_code_return.c b/vivified/code/vivi_code_return.c
index e2f0dfa..0c1ca00 100644
--- a/vivified/code/vivi_code_return.c
+++ b/vivified/code/vivi_code_return.c
@@ -29,8 +29,8 @@ G_DEFINE_TYPE (ViviCodeReturn, vivi_code_return, VIVI_TYPE_CODE_STATEMENT)
 static void
 vivi_code_return_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
-  vivi_code_printer_new_line (printer, FALSE);
   vivi_code_printer_print (printer, "return;");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
diff --git a/vivified/code/vivi_code_text_printer.c b/vivified/code/vivi_code_text_printer.c
index cc1b5b8..e4a6c37 100644
--- a/vivified/code/vivi_code_text_printer.c
+++ b/vivified/code/vivi_code_text_printer.c
@@ -36,15 +36,22 @@ vivi_code_text_printer_dispose (GObject *object)
 static void
 vivi_code_text_printer_print (ViviCodePrinter *printer, const char *text)
 {
+  ViviCodeTextPrinter *tp = VIVI_CODE_TEXT_PRINTER (printer);
+
+  if (tp->need_indent) {
+    g_print ("%*s", vivi_code_printer_get_indentation (printer) * 2, "");
+    tp->need_indent = FALSE;
+  }
   g_print ("%s", text);
 }
 
 static void
 vivi_code_text_printer_new_line (ViviCodePrinter *printer, gboolean ignore_indentation)
 {
+  ViviCodeTextPrinter *text = VIVI_CODE_TEXT_PRINTER (printer);
+
   g_print ("\n");
-  if (!ignore_indentation)
-    g_print ("%*s", vivi_code_printer_get_indentation (printer) * 2, "");
+  text->need_indent = !ignore_indentation;
 }
 
 static void
@@ -60,8 +67,9 @@ vivi_code_text_printer_class_init (ViviCodeTextPrinterClass *klass)
 }
 
 static void
-vivi_code_text_printer_init (ViviCodeTextPrinter *text_printer)
+vivi_code_text_printer_init (ViviCodeTextPrinter *tp)
 {
+  tp->need_indent = TRUE;
 }
 
 ViviCodePrinter *
diff --git a/vivified/code/vivi_code_text_printer.h b/vivified/code/vivi_code_text_printer.h
index d8b05c9..d44faf8 100644
--- a/vivified/code/vivi_code_text_printer.h
+++ b/vivified/code/vivi_code_text_printer.h
@@ -38,6 +38,8 @@ typedef struct _ViviCodeTextPrinterClass ViviCodeTextPrinterClass;
 struct _ViviCodeTextPrinter
 {
   ViviCodePrinter	printer;
+
+  gboolean		need_indent;	/* need to print indentation */
 };
 
 struct _ViviCodeTextPrinterClass
diff --git a/vivified/code/vivi_code_trace.c b/vivified/code/vivi_code_trace.c
index efbe6d9..e87a728 100644
--- a/vivified/code/vivi_code_trace.c
+++ b/vivified/code/vivi_code_trace.c
@@ -41,10 +41,10 @@ vivi_code_trace_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeTrace *trace = VIVI_CODE_TRACE (token);
 
-  vivi_code_printer_new_line (printer, FALSE);
   vivi_code_printer_print (printer, "trace (");
   vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (trace->value));
   vivi_code_printer_print (printer, ");");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
diff --git a/vivified/code/vivi_code_value_statement.c b/vivified/code/vivi_code_value_statement.c
index 4a432c5..79e05ce 100644
--- a/vivified/code/vivi_code_value_statement.c
+++ b/vivified/code/vivi_code_value_statement.c
@@ -41,9 +41,9 @@ vivi_code_value_statement_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeValueStatement *stmt = VIVI_CODE_VALUE_STATEMENT (token);
 
-  vivi_code_printer_new_line (printer, FALSE);
   vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->value));
   vivi_code_printer_print (printer, ";");
+  vivi_code_printer_new_line (printer, FALSE);
 }
 
 static void
commit e11b48ca07e3cfd754e4b3dcfda3b2a777340c3e
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 19:10:25 2008 +0100

    improve test output on failure

diff --git a/vivified/code/test/Makefile.am b/vivified/code/test/Makefile.am
index 0ad16b9..f6581d6 100644
--- a/vivified/code/test/Makefile.am
+++ b/vivified/code/test/Makefile.am
@@ -1,9 +1,17 @@
 check-local: ../vivi-decompile
-	RESULT=0; \
+	RESULT=""; \
 	for file in $(srcdir)/*.swf; do \
-	  ../vivi-decompile $$file | diff -u $$file.expect - || RESULT=1; \
+	  ../vivi-decompile $$file | diff -u $$file.expect - || RESULT="$$RESULT $$file"; \
 	done; \
-	exit $$RESULT
+	if test "x$$RESULT" == "x"; then \
+	  echo "OK"; \
+	else \
+	  echo "FAILED:"; \
+	  for fail in $$RESULT; do \
+	    echo "  $$fail"; \
+	  done; \
+	  exit 1; \
+	fi
 
 EXTRA_DIST = \
 	hello-world.as \
commit 48437aa66ab5f5f68525fc98f52393a9d778c9a4
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 18:49:17 2008 +0100

    add a vivi_code_statement_needs_braces function

diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index d127edf..d0978d1 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -55,6 +55,14 @@ vivi_code_block_optimize (ViviCodeStatement *stmt)
   return g_object_ref (block);
 }
 
+static gboolean
+vivi_code_block_needs_braces (ViviCodeStatement *stmt)
+{
+  ViviCodeBlock *block = VIVI_CODE_BLOCK (stmt);
+
+  return g_queue_get_length (block->statements) > 1;
+}
+
 static void
 vivi_code_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
@@ -96,6 +104,7 @@ vivi_code_block_class_init (ViviCodeBlockClass *klass)
   token_class->print = vivi_code_block_print;
 
   statement_class->optimize = vivi_code_block_optimize;
+  statement_class->needs_braces = vivi_code_block_needs_braces;
 }
 
 static void
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index de2b197..b2b9a54 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -73,6 +73,13 @@ vivi_code_if_optimize (ViviCodeStatement *statement)
   return VIVI_CODE_STATEMENT (stmt);
 }
 
+static gboolean
+vivi_code_if_needs_braces (ViviCodeStatement *stmt)
+{
+  /* only set because it makes code way more readable, especially on nested ifs */
+  return TRUE;
+}
+
 static void
 vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
@@ -109,6 +116,7 @@ vivi_code_if_class_init (ViviCodeIfClass *klass)
   token_class->print = vivi_code_if_print;
 
   statement_class->optimize = vivi_code_if_optimize;
+  statement_class->needs_braces = vivi_code_if_needs_braces;
 }
 
 static void
diff --git a/vivified/code/vivi_code_statement.c b/vivified/code/vivi_code_statement.c
index ff88331..e8700ad 100644
--- a/vivified/code/vivi_code_statement.c
+++ b/vivified/code/vivi_code_statement.c
@@ -62,3 +62,18 @@ vivi_code_statement_optimize (ViviCodeStatement *stmt)
   }
 }
 
+gboolean
+vivi_code_statement_needs_braces (ViviCodeStatement *stmt)
+{
+  ViviCodeStatementClass *klass;
+
+  g_return_val_if_fail (VIVI_IS_CODE_STATEMENT (stmt), FALSE);
+
+  klass = VIVI_CODE_STATEMENT_GET_CLASS (stmt);
+  if (klass->needs_braces) {
+    return klass->needs_braces (stmt);
+  } else {
+    return FALSE;
+  }
+}
+
diff --git a/vivified/code/vivi_code_statement.h b/vivified/code/vivi_code_statement.h
index d1f1bc7..60326a8 100644
--- a/vivified/code/vivi_code_statement.h
+++ b/vivified/code/vivi_code_statement.h
@@ -44,12 +44,14 @@ struct _ViviCodeStatementClass
 {
   ViviCodeTokenClass	token_class;
 
+  gboolean		(* needs_braces)		(ViviCodeStatement *	stmt);
   ViviCodeStatement *	(* optimize)			(ViviCodeStatement *	stmt);
 };
 
 GType			vivi_code_statement_get_type   	(void);
 
 ViviCodeStatement *   	vivi_code_statement_optimize	(ViviCodeStatement *	stmt);
+gboolean		vivi_code_statement_needs_braces(ViviCodeStatement *	stmt);
 
 G_END_DECLS
 #endif
commit 75001bdabc81fdd3c26c7eb1e5aae49e50fcbfcc
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 18:49:04 2008 +0100

    output correct diffs

diff --git a/vivified/code/test/Makefile.am b/vivified/code/test/Makefile.am
index 735dbd9..0ad16b9 100644
--- a/vivified/code/test/Makefile.am
+++ b/vivified/code/test/Makefile.am
@@ -1,7 +1,7 @@
 check-local: ../vivi-decompile
 	RESULT=0; \
 	for file in $(srcdir)/*.swf; do \
-	  ../vivi-decompile $$file | diff -u - $$file.expect || RESULT=1; \
+	  ../vivi-decompile $$file | diff -u $$file.expect - || RESULT=1; \
 	done; \
 	exit $$RESULT
 
commit e527dabaa648c061171b3708c8adc593fca3af2a
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 17:14:48 2008 +0100

    make statements and values have different optimize functions

diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index dbf28b6..d127edf 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -42,10 +42,10 @@ vivi_code_block_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_block_parent_class)->dispose (object);
 }
 
-static ViviCodeToken *
-vivi_code_block_optimize (ViviCodeToken *token)
+static ViviCodeStatement *
+vivi_code_block_optimize (ViviCodeStatement *stmt)
 {
-  ViviCodeBlock *block = VIVI_CODE_BLOCK (token);
+  ViviCodeBlock *block = VIVI_CODE_BLOCK (stmt);
   guint length;
 
   length = g_queue_get_length (block->statements);
@@ -89,11 +89,13 @@ vivi_code_block_class_init (ViviCodeBlockClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeStatementClass *statement_class = VIVI_CODE_STATEMENT_CLASS (klass);
 
   object_class->dispose = vivi_code_block_dispose;
 
   token_class->print = vivi_code_block_print;
-  token_class->optimize = vivi_code_block_optimize;
+
+  statement_class->optimize = vivi_code_block_optimize;
 }
 
 static void
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 3fe43cf..de2b197 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -41,17 +41,15 @@ vivi_code_if_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_if_parent_class)->dispose (object);
 }
 
-static ViviCodeToken *
-vivi_code_if_optimize (ViviCodeToken *token)
+static ViviCodeStatement *
+vivi_code_if_optimize (ViviCodeStatement *statement)
 {
-  ViviCodeIf *stmt = VIVI_CODE_IF (token);
+  ViviCodeIf *stmt = VIVI_CODE_IF (statement);
   ViviCodeStatement *if_stmt, *else_stmt;
   ViviCodeValue *cond, *tmp;
 
-  if_stmt = stmt->if_statement ? VIVI_CODE_STATEMENT (vivi_code_token_optimize (
-	VIVI_CODE_TOKEN (stmt->if_statement))) : NULL;
-  else_stmt = stmt->else_statement ? VIVI_CODE_STATEMENT (
-      vivi_code_token_optimize (VIVI_CODE_TOKEN (stmt->else_statement))) : NULL;
+  if_stmt = stmt->if_statement ? vivi_code_statement_optimize (stmt->if_statement) : NULL;
+  else_stmt = stmt->else_statement ? vivi_code_statement_optimize (stmt->else_statement) : NULL;
 #if 0
   if (if_stmt == NULL && else_stmt == NULL)
     return NULL;
@@ -63,7 +61,7 @@ vivi_code_if_optimize (ViviCodeToken *token)
     if_stmt = else_stmt;
     else_stmt = NULL;
   }
-  tmp = VIVI_CODE_VALUE (vivi_code_token_optimize (VIVI_CODE_TOKEN (cond)));
+  tmp = vivi_code_value_optimize (cond, SWFDEC_AS_TYPE_BOOLEAN);
   g_object_unref (cond);
   cond = tmp;
 
@@ -72,7 +70,7 @@ vivi_code_if_optimize (ViviCodeToken *token)
     vivi_code_if_set_if (stmt, if_stmt);
   if (else_stmt)
     vivi_code_if_set_else (stmt, else_stmt);
-  return VIVI_CODE_TOKEN (stmt);
+  return VIVI_CODE_STATEMENT (stmt);
 }
 
 static void
@@ -104,11 +102,13 @@ vivi_code_if_class_init (ViviCodeIfClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeStatementClass *statement_class = VIVI_CODE_STATEMENT_CLASS (klass);
 
   object_class->dispose = vivi_code_if_dispose;
 
-  token_class->optimize = vivi_code_if_optimize;
   token_class->print = vivi_code_if_print;
+
+  statement_class->optimize = vivi_code_if_optimize;
 }
 
 static void
diff --git a/vivified/code/vivi_code_statement.c b/vivified/code/vivi_code_statement.c
index 1a3b76e..ff88331 100644
--- a/vivified/code/vivi_code_statement.c
+++ b/vivified/code/vivi_code_statement.c
@@ -46,3 +46,19 @@ vivi_code_statement_init (ViviCodeStatement *token)
 {
 }
 
+ViviCodeStatement *
+vivi_code_statement_optimize (ViviCodeStatement *stmt)
+{
+  ViviCodeStatementClass *klass;
+
+  g_return_val_if_fail (VIVI_IS_CODE_STATEMENT (stmt), NULL);
+
+  klass = VIVI_CODE_STATEMENT_GET_CLASS (stmt);
+  if (klass->optimize) {
+    ViviCodeStatement *ret = klass->optimize (stmt);
+    return ret;
+  } else {
+    return g_object_ref (stmt);
+  }
+}
+
diff --git a/vivified/code/vivi_code_statement.h b/vivified/code/vivi_code_statement.h
index 9a4215a..d1f1bc7 100644
--- a/vivified/code/vivi_code_statement.h
+++ b/vivified/code/vivi_code_statement.h
@@ -43,10 +43,13 @@ struct _ViviCodeStatement
 struct _ViviCodeStatementClass
 {
   ViviCodeTokenClass	token_class;
+
+  ViviCodeStatement *	(* optimize)			(ViviCodeStatement *	stmt);
 };
 
 GType			vivi_code_statement_get_type   	(void);
 
+ViviCodeStatement *   	vivi_code_statement_optimize	(ViviCodeStatement *	stmt);
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_token.c b/vivified/code/vivi_code_token.c
index 0f4dab1..e722aa8 100644
--- a/vivified/code/vivi_code_token.c
+++ b/vivified/code/vivi_code_token.c
@@ -46,19 +46,3 @@ vivi_code_token_init (ViviCodeToken *token)
 {
 }
 
-ViviCodeToken *
-vivi_code_token_optimize (ViviCodeToken *token)
-{
-  ViviCodeTokenClass *klass;
-
-  g_return_val_if_fail (VIVI_IS_CODE_TOKEN (token), NULL);
-
-  klass = VIVI_CODE_TOKEN_GET_CLASS (token);
-  if (klass->optimize) {
-    ViviCodeToken *ret = klass->optimize (token);
-    return ret;
-  } else {
-    return g_object_ref (token);
-  }
-}
-
diff --git a/vivified/code/vivi_code_token.h b/vivified/code/vivi_code_token.h
index 6bbc120..afdee1a 100644
--- a/vivified/code/vivi_code_token.h
+++ b/vivified/code/vivi_code_token.h
@@ -48,13 +48,10 @@ struct _ViviCodeTokenClass
 
   void			(* print)			(ViviCodeToken *	token,
 							 ViviCodePrinter *	printer);
-  ViviCodeToken *	(* optimize)			(ViviCodeToken *	token);
 };
 
 GType			vivi_code_token_get_type   	(void);
 
-ViviCodeToken *		vivi_code_token_optimize	(ViviCodeToken *	token);
-
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
index 2b76f14..60fb26e 100644
--- a/vivified/code/vivi_code_unary.c
+++ b/vivified/code/vivi_code_unary.c
@@ -36,17 +36,19 @@ vivi_code_unary_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_unary_parent_class)->dispose (object);
 }
 
-static ViviCodeToken * 
-vivi_code_unary_optimize (ViviCodeToken *token)
+static ViviCodeValue * 
+vivi_code_unary_optimize (ViviCodeValue *value, SwfdecAsValueType hint)
 {
-  ViviCodeUnary *unary = VIVI_CODE_UNARY (token);
+  ViviCodeUnary *unary = VIVI_CODE_UNARY (value);
 
   if (unary->operation == '!' && 
+      hint == SWFDEC_AS_TYPE_BOOLEAN &&
       VIVI_IS_CODE_UNARY (unary->value) && 
       VIVI_CODE_UNARY (unary->value)->operation == unary->operation) {
-    return vivi_code_token_optimize (VIVI_CODE_TOKEN (VIVI_CODE_UNARY (unary->value)->value));
+    return vivi_code_value_optimize (VIVI_CODE_UNARY (unary->value)->value, hint);
   }
 
+  /* FIXME: optimize unary->value */
   return g_object_ref (unary);
 }
 
@@ -80,9 +82,9 @@ vivi_code_unary_class_init (ViviCodeUnaryClass *klass)
   object_class->dispose = vivi_code_unary_dispose;
 
   token_class->print = vivi_code_unary_print;
-  token_class->optimize = vivi_code_unary_optimize;
 
   value_class->is_constant = vivi_code_unary_is_constant;
+  value_class->optimize = vivi_code_unary_optimize;
 }
 
 static void
diff --git a/vivified/code/vivi_code_value.c b/vivified/code/vivi_code_value.c
index 99d4d5a..e5339c7 100644
--- a/vivified/code/vivi_code_value.c
+++ b/vivified/code/vivi_code_value.c
@@ -76,3 +76,19 @@ vivi_code_value_get_precedence (ViviCodeValue *value)
   return value->precedence;
 }
 
+ViviCodeValue *
+vivi_code_value_optimize (ViviCodeValue *value, SwfdecAsValueType hint)
+{
+  ViviCodeValueClass *klass;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  klass = VIVI_CODE_VALUE_GET_CLASS (value);
+  if (klass->optimize) {
+    ViviCodeValue *ret = klass->optimize (value, hint);
+    return ret;
+  } else {
+    return g_object_ref (value);
+  }
+}
+
diff --git a/vivified/code/vivi_code_value.h b/vivified/code/vivi_code_value.h
index 6a8b9af..924b310 100644
--- a/vivified/code/vivi_code_value.h
+++ b/vivified/code/vivi_code_value.h
@@ -71,6 +71,8 @@ struct _ViviCodeValueClass
   ViviCodeTokenClass  	token_class;
 
   gboolean		(* is_constant)			(ViviCodeValue *	value);
+  ViviCodeValue *	(* optimize)			(ViviCodeValue *	value,
+							 SwfdecAsValueType	hint);
 };
 
 GType			vivi_code_value_get_type   	(void);
@@ -81,6 +83,9 @@ void			vivi_code_value_set_precedence	(ViviCodeValue *	value,
 							 ViviPrecedence		precedence);
 ViviPrecedence		vivi_code_value_get_precedence	(ViviCodeValue *	value);
 
+ViviCodeValue *		vivi_code_value_optimize	(ViviCodeValue *	value,
+							 SwfdecAsValueType	hint);
+
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 965e1ea..58a0bd4 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -541,7 +541,7 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block, *if_block, *else_block;
   ViviCodeIf *if_stmt;
-  ViviCodeToken *token;
+  ViviCodeStatement *stmt;
   gboolean result;
   GList *walk;
 
@@ -596,11 +596,10 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       vivi_decompiler_purge_block (dec, else_block);
       vivi_code_if_set_else (if_stmt, VIVI_CODE_STATEMENT (tmp));
     }
-    token = vivi_code_token_optimize (VIVI_CODE_TOKEN (if_stmt));
+    stmt = vivi_code_statement_optimize (VIVI_CODE_STATEMENT (if_stmt));
     g_object_unref (if_stmt);
-    if (token)
-      vivi_code_block_add_statement (VIVI_CODE_BLOCK (block),
-	  VIVI_CODE_STATEMENT (token));
+    if (stmt)
+      vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), stmt);
     result = TRUE;
   }
 
commit 04ce881e2caaafa0a1b343318b5b7992ac5ab0d7
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 16:51:17 2008 +0100

    add optimizing support
    
    in particular optimize if statements and !!

diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index d9ec30a..dbf28b6 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -42,6 +42,19 @@ vivi_code_block_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_block_parent_class)->dispose (object);
 }
 
+static ViviCodeToken *
+vivi_code_block_optimize (ViviCodeToken *token)
+{
+  ViviCodeBlock *block = VIVI_CODE_BLOCK (token);
+  guint length;
+
+  length = g_queue_get_length (block->statements);
+  if (length == 0)
+    return NULL;
+
+  return g_object_ref (block);
+}
+
 static void
 vivi_code_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
@@ -80,6 +93,7 @@ vivi_code_block_class_init (ViviCodeBlockClass *klass)
   object_class->dispose = vivi_code_block_dispose;
 
   token_class->print = vivi_code_block_print;
+  token_class->optimize = vivi_code_block_optimize;
 }
 
 static void
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 04f2914..3fe43cf 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -23,6 +23,7 @@
 
 #include "vivi_code_if.h"
 #include "vivi_code_printer.h"
+#include "vivi_code_unary.h"
 
 G_DEFINE_TYPE (ViviCodeIf, vivi_code_if, VIVI_TYPE_CODE_STATEMENT)
 
@@ -40,6 +41,40 @@ vivi_code_if_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_if_parent_class)->dispose (object);
 }
 
+static ViviCodeToken *
+vivi_code_if_optimize (ViviCodeToken *token)
+{
+  ViviCodeIf *stmt = VIVI_CODE_IF (token);
+  ViviCodeStatement *if_stmt, *else_stmt;
+  ViviCodeValue *cond, *tmp;
+
+  if_stmt = stmt->if_statement ? VIVI_CODE_STATEMENT (vivi_code_token_optimize (
+	VIVI_CODE_TOKEN (stmt->if_statement))) : NULL;
+  else_stmt = stmt->else_statement ? VIVI_CODE_STATEMENT (
+      vivi_code_token_optimize (VIVI_CODE_TOKEN (stmt->else_statement))) : NULL;
+#if 0
+  if (if_stmt == NULL && else_stmt == NULL)
+    return NULL;
+#endif
+
+  cond = g_object_ref (stmt->condition);
+  if (if_stmt == NULL && else_stmt != NULL) {
+    cond = VIVI_CODE_VALUE (vivi_code_unary_new (cond, '!'));
+    if_stmt = else_stmt;
+    else_stmt = NULL;
+  }
+  tmp = VIVI_CODE_VALUE (vivi_code_token_optimize (VIVI_CODE_TOKEN (cond)));
+  g_object_unref (cond);
+  cond = tmp;
+
+  stmt = VIVI_CODE_IF (vivi_code_if_new (cond));
+  if (if_stmt)
+    vivi_code_if_set_if (stmt, if_stmt);
+  if (else_stmt)
+    vivi_code_if_set_else (stmt, else_stmt);
+  return VIVI_CODE_TOKEN (stmt);
+}
+
 static void
 vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
@@ -72,6 +107,7 @@ vivi_code_if_class_init (ViviCodeIfClass *klass)
 
   object_class->dispose = vivi_code_if_dispose;
 
+  token_class->optimize = vivi_code_if_optimize;
   token_class->print = vivi_code_if_print;
 }
 
diff --git a/vivified/code/vivi_code_token.c b/vivified/code/vivi_code_token.c
index e722aa8..0f4dab1 100644
--- a/vivified/code/vivi_code_token.c
+++ b/vivified/code/vivi_code_token.c
@@ -46,3 +46,19 @@ vivi_code_token_init (ViviCodeToken *token)
 {
 }
 
+ViviCodeToken *
+vivi_code_token_optimize (ViviCodeToken *token)
+{
+  ViviCodeTokenClass *klass;
+
+  g_return_val_if_fail (VIVI_IS_CODE_TOKEN (token), NULL);
+
+  klass = VIVI_CODE_TOKEN_GET_CLASS (token);
+  if (klass->optimize) {
+    ViviCodeToken *ret = klass->optimize (token);
+    return ret;
+  } else {
+    return g_object_ref (token);
+  }
+}
+
diff --git a/vivified/code/vivi_code_token.h b/vivified/code/vivi_code_token.h
index afdee1a..6bbc120 100644
--- a/vivified/code/vivi_code_token.h
+++ b/vivified/code/vivi_code_token.h
@@ -48,10 +48,13 @@ struct _ViviCodeTokenClass
 
   void			(* print)			(ViviCodeToken *	token,
 							 ViviCodePrinter *	printer);
+  ViviCodeToken *	(* optimize)			(ViviCodeToken *	token);
 };
 
 GType			vivi_code_token_get_type   	(void);
 
+ViviCodeToken *		vivi_code_token_optimize	(ViviCodeToken *	token);
+
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
index 4c86ea1..2b76f14 100644
--- a/vivified/code/vivi_code_unary.c
+++ b/vivified/code/vivi_code_unary.c
@@ -36,6 +36,20 @@ vivi_code_unary_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_unary_parent_class)->dispose (object);
 }
 
+static ViviCodeToken * 
+vivi_code_unary_optimize (ViviCodeToken *token)
+{
+  ViviCodeUnary *unary = VIVI_CODE_UNARY (token);
+
+  if (unary->operation == '!' && 
+      VIVI_IS_CODE_UNARY (unary->value) && 
+      VIVI_CODE_UNARY (unary->value)->operation == unary->operation) {
+    return vivi_code_token_optimize (VIVI_CODE_TOKEN (VIVI_CODE_UNARY (unary->value)->value));
+  }
+
+  return g_object_ref (unary);
+}
+
 static void
 vivi_code_unary_print (ViviCodeToken *token, ViviCodePrinter*printer)
 {
@@ -66,6 +80,7 @@ vivi_code_unary_class_init (ViviCodeUnaryClass *klass)
   object_class->dispose = vivi_code_unary_dispose;
 
   token_class->print = vivi_code_unary_print;
+  token_class->optimize = vivi_code_unary_optimize;
 
   value_class->is_constant = vivi_code_unary_is_constant;
 }
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index b2300e1..965e1ea 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -541,6 +541,7 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block, *if_block, *else_block;
   ViviCodeIf *if_stmt;
+  ViviCodeToken *token;
   gboolean result;
   GList *walk;
 
@@ -595,8 +596,11 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       vivi_decompiler_purge_block (dec, else_block);
       vivi_code_if_set_else (if_stmt, VIVI_CODE_STATEMENT (tmp));
     }
-    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block),
-	VIVI_CODE_STATEMENT (if_stmt));
+    token = vivi_code_token_optimize (VIVI_CODE_TOKEN (if_stmt));
+    g_object_unref (if_stmt);
+    if (token)
+      vivi_code_block_add_statement (VIVI_CODE_BLOCK (block),
+	  VIVI_CODE_STATEMENT (token));
     result = TRUE;
   }
 
commit 4722f60432f8fb72bd669f018eb2bd7e4593e11f
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 15:04:23 2008 +0100

    unset next and branch befre appending block
    
    otherwise we'd end up with goto statements

diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
index 3944ded..b2300e1 100644
--- a/vivified/code/vivi_decompiler.c
+++ b/vivified/code/vivi_decompiler.c
@@ -513,7 +513,6 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec)
     if (vivi_decompiler_block_get_n_incoming (next) != 1)
       continue;
 
-    vivi_decompiler_block_add_to_block (next, VIVI_CODE_BLOCK (block));
     vivi_decompiler_block_set_next (block, vivi_decompiler_block_get_next (next));
     val = vivi_decompiler_block_get_branch_condition (next);
     if (val) {
@@ -521,7 +520,11 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec)
 	  vivi_decompiler_block_get_branch (next),
 	  g_object_ref (val));
     }
+    vivi_decompiler_block_set_next (next, NULL);
+    vivi_decompiler_block_set_branch (next, NULL, NULL);
+    vivi_decompiler_block_add_to_block (next, VIVI_CODE_BLOCK (block));
     vivi_decompiler_purge_block (dec, next);
+    result = TRUE;
   }
 
   return result;
commit 564b787baa9bea06a46496c98e0afb6e00e4fccf
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed Mar 19 14:46:27 2008 +0100

    add a printer class that takes care of properly printing stuff
    
    It should also be good enough for producing annotated GtkTextBuffers

diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
index 4e339d0..c83bd0f 100644
--- a/vivified/code/Makefile.am
+++ b/vivified/code/Makefile.am
@@ -13,8 +13,10 @@ libvivified_compiler_la_SOURCES = \
 	vivi_code_goto.c \
 	vivi_code_if.c \
 	vivi_code_label.c \
+	vivi_code_printer.c \
 	vivi_code_return.c \
 	vivi_code_statement.c \
+	vivi_code_text_printer.c \
 	vivi_code_token.c \
 	vivi_code_trace.c \
 	vivi_code_unary.c \
@@ -32,8 +34,10 @@ noinst_HEADERS = \
 	vivi_code_goto.h \
 	vivi_code_if.h \
 	vivi_code_label.h \
+	vivi_code_printer.h \
 	vivi_code_return.h \
 	vivi_code_statement.h \
+	vivi_code_text_printer.h \
 	vivi_code_token.h \
 	vivi_code_trace.h \
 	vivi_code_unary.h \
diff --git a/vivified/code/decompiler.c b/vivified/code/decompiler.c
index e5927f2..1626172 100644
--- a/vivified/code/decompiler.c
+++ b/vivified/code/decompiler.c
@@ -28,6 +28,7 @@
 #include <swfdec/swfdec_sprite_movie.h>
 #include <swfdec/swfdec_swf_decoder.h>
 
+#include "vivi_code_text_printer.h"
 #include "vivi_decompiler.h"
 
 static void
@@ -36,13 +37,14 @@ decode_script (gpointer offset, gpointer scriptp, gpointer unused)
   SwfdecScript *script = scriptp;
   ViviDecompiler *dec = vivi_decompiler_new (scriptp);
   ViviCodeToken *token;
-  char *s;
+  ViviCodePrinter *printer;
 
   g_print ("/* %s */\n", script->name);
   token = VIVI_CODE_TOKEN (vivi_decompiler_get_block (dec));
-  s = vivi_code_token_to_code (token);
-  g_print ("%s\n", s);
-  g_free (s);
+  printer = vivi_code_text_printer_new ();
+  vivi_code_printer_print_token (printer, token);
+  vivi_code_printer_new_line (printer, FALSE);
+  g_object_unref (printer);
   g_object_unref (dec);
 }
 
diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
index c19a75d..d9ec30a 100644
--- a/vivified/code/vivi_code_block.c
+++ b/vivified/code/vivi_code_block.c
@@ -27,6 +27,7 @@
 #include "vivi_code_block.h"
 #include "vivi_code_comment.h"
 #include "vivi_code_label.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeBlock, vivi_code_block, VIVI_TYPE_CODE_STATEMENT)
 
@@ -41,31 +42,33 @@ vivi_code_block_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_block_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_block_to_code (ViviCodeToken *token)
+static void
+vivi_code_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeBlock *block = VIVI_CODE_BLOCK (token);
-  GString *string;
-  char *s;
   guint length;
-  GList *walk;
 
   length = g_queue_get_length (block->statements);
-  if (length == 0)
-    return g_strdup ("  ;");
-
-  string = g_string_new ("");
-  if (length > 1)
-    g_string_append (string, "{\n");
-  for (walk = g_queue_peek_head_link (block->statements); walk; walk = walk->next) {
-    s = vivi_code_token_to_code (walk->data);
-    g_string_append (string, s);
-    g_free (s);
+  if (length > 1) {
+    vivi_code_printer_new_line (printer, FALSE);
+    vivi_code_printer_print (printer, "{");
+  }
+  vivi_code_printer_push_indentation (printer);
+  if (length == 0) {
+    vivi_code_printer_new_line (printer, FALSE);
+    vivi_code_printer_print (printer, ";");
+  } else {
+    GList *walk;
+
+    for (walk = g_queue_peek_head_link (block->statements); walk; walk = walk->next) {
+      vivi_code_printer_print_token (printer, walk->data);
+    }
+  }
+  vivi_code_printer_pop_indentation (printer);
+  if (length > 1) {
+    vivi_code_printer_new_line (printer, FALSE);
+    vivi_code_printer_print (printer, "}");
   }
-  if (length > 1)
-    g_string_append (string, "}\n");
-
-  return g_string_free (string, FALSE);
 }
 
 static void
@@ -76,7 +79,7 @@ vivi_code_block_class_init (ViviCodeBlockClass *klass)
 
   object_class->dispose = vivi_code_block_dispose;
 
-  token_class->to_code = vivi_code_block_to_code;
+  token_class->print = vivi_code_block_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_comment.c b/vivified/code/vivi_code_comment.c
index 58ead10..31bce87 100644
--- a/vivified/code/vivi_code_comment.c
+++ b/vivified/code/vivi_code_comment.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_comment.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeComment, vivi_code_comment, VIVI_TYPE_CODE_STATEMENT)
 
@@ -35,12 +36,15 @@ vivi_code_comment_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_comment_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_comment_to_code (ViviCodeToken *token)
+static void
+vivi_code_comment_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeComment *comment = VIVI_CODE_COMMENT (token);
 
-  return g_strdup_printf ("/* %s */\n", comment->comment);
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_print (printer, "/* ");
+  vivi_code_printer_print (printer, comment->comment);
+  vivi_code_printer_print (printer, " */");
 }
 
 static void
@@ -51,7 +55,7 @@ vivi_code_comment_class_init (ViviCodeCommentClass *klass)
 
   object_class->dispose = vivi_code_comment_dispose;
 
-  token_class->to_code = vivi_code_comment_to_code;
+  token_class->print = vivi_code_comment_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
index d7f4ad6..e432007 100644
--- a/vivified/code/vivi_code_constant.c
+++ b/vivified/code/vivi_code_constant.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_constant.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeConstant, vivi_code_constant, VIVI_TYPE_CODE_VALUE)
 
@@ -35,12 +36,12 @@ vivi_code_constant_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_constant_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_constant_to_code (ViviCodeToken *token)
+static void
+vivi_code_constant_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeConstant *constant = VIVI_CODE_CONSTANT (token);
 
-  return g_strdup (constant->text);
+  vivi_code_printer_print (printer, constant->text);
 }
 
 static gboolean
@@ -58,7 +59,7 @@ vivi_code_constant_class_init (ViviCodeConstantClass *klass)
 
   object_class->dispose = vivi_code_constant_dispose;
 
-  token_class->to_code = vivi_code_constant_to_code;
+  token_class->print = vivi_code_constant_print;
 
   value_class->is_constant = vivi_code_constant_is_constant;
 }
diff --git a/vivified/code/vivi_code_get_url.c b/vivified/code/vivi_code_get_url.c
index 0791769..1fcc676 100644
--- a/vivified/code/vivi_code_get_url.c
+++ b/vivified/code/vivi_code_get_url.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_get_url.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeGetUrl, vivi_code_get_url, VIVI_TYPE_CODE_STATEMENT)
 
@@ -36,32 +37,28 @@ vivi_code_get_url_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_get_url_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_get_url_to_code (ViviCodeToken *token)
+static void
+vivi_code_get_url_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeGetUrl *url = VIVI_CODE_GET_URL (token);
-  char *t, *u, *ret;
-  const char *name;
+
+  vivi_code_printer_new_line (printer, FALSE);
 
   if (url->variables) {
-    name = "loadVariables";
+    vivi_code_printer_print (printer, "loadVariables (");
   } else if (url->internal) {
-    name = "loadMovie";
+    vivi_code_printer_print (printer, "loadMovie (");
   } else {
-    name = "getURL";
+    vivi_code_printer_print (printer, "getURL (");
   }
-  u = vivi_code_token_to_code (VIVI_CODE_TOKEN (url->url));
-  t = vivi_code_token_to_code (VIVI_CODE_TOKEN (url->target));
-  if (url->method == 0) {
-    ret = g_strdup_printf ("%s (%s, %s);\n", name, u, t);
-  } else {
-    ret = g_strdup_printf ("%s (%s, %s, %s);\n", name, u, t,
-	url->method == 2 ? "\"POST\"" : "\"GET\"");
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (url->url));
+  vivi_code_printer_print (printer, ", ");
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (url->target));
+  if (url->method != 0) {
+    vivi_code_printer_print (printer,
+	url->method == 2 ? ", \"POST\"" : ", \"GET\"");
   }
-  g_free (t);
-  g_free (u);
-
-  return ret;
+  vivi_code_printer_print (printer, ");");
 }
 
 static void
@@ -72,7 +69,7 @@ vivi_code_get_url_class_init (ViviCodeGetUrlClass *klass)
 
   object_class->dispose = vivi_code_get_url_dispose;
 
-  token_class->to_code = vivi_code_get_url_to_code;
+  token_class->print = vivi_code_get_url_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_goto.c b/vivified/code/vivi_code_goto.c
index e92b7f7..4f33be4 100644
--- a/vivified/code/vivi_code_goto.c
+++ b/vivified/code/vivi_code_goto.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_goto.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeGoto, vivi_code_goto, VIVI_TYPE_CODE_STATEMENT)
 
@@ -35,12 +36,15 @@ vivi_code_goto_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_goto_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_goto_to_code (ViviCodeToken *token)
+static void
+vivi_code_goto_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeGoto *gotoo = VIVI_CODE_GOTO (token);
 
-  return g_strdup_printf ("  goto %s;\n", vivi_code_label_get_name (gotoo->label));
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_print (printer, "goto ");
+  vivi_code_printer_print (printer, vivi_code_label_get_name (gotoo->label));
+  vivi_code_printer_print (printer, ";");
 }
 
 static void
@@ -51,7 +55,7 @@ vivi_code_goto_class_init (ViviCodeGotoClass *klass)
 
   object_class->dispose = vivi_code_goto_dispose;
 
-  token_class->to_code = vivi_code_goto_to_code;
+  token_class->print = vivi_code_goto_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
index 3c5bc97..04f2914 100644
--- a/vivified/code/vivi_code_if.c
+++ b/vivified/code/vivi_code_if.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_if.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeIf, vivi_code_if, VIVI_TYPE_CODE_STATEMENT)
 
@@ -39,32 +40,28 @@ vivi_code_if_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_if_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_if_to_code (ViviCodeToken *token)
+static void
+vivi_code_if_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeIf *stmt = VIVI_CODE_IF (token);
-  GString *string;
-  char *s;
 
-  string = g_string_new ("");
-  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->condition));
-  g_string_append_printf (string, "if (%s)\n", s);
-  g_free (s);
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_print (printer, "if (");
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->condition));
+  vivi_code_printer_print (printer, ")");
   if (stmt->if_statement) {
-    s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->if_statement));
-    g_string_append (string, s);
-    g_free (s);
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->if_statement));
   } else {
-    g_string_append (string, "  ;\n");
+    vivi_code_printer_push_indentation (printer);
+    vivi_code_printer_new_line (printer, FALSE);
+    vivi_code_printer_print (printer, ";");
+    vivi_code_printer_pop_indentation (printer);
   }
   if (stmt->else_statement) {
-    g_string_append (string, "else");
-    s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->else_statement));
-    g_string_append (string, s);
-    g_free (s);
+    vivi_code_printer_new_line (printer, FALSE);
+    vivi_code_printer_print (printer, "else");
+    vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->else_statement));
   }
-
-  return g_string_free (string, FALSE);
 }
 
 static void
@@ -75,7 +72,7 @@ vivi_code_if_class_init (ViviCodeIfClass *klass)
 
   object_class->dispose = vivi_code_if_dispose;
 
-  token_class->to_code = vivi_code_if_to_code;
+  token_class->print = vivi_code_if_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_label.c b/vivified/code/vivi_code_label.c
index d860ce3..85a0ce5 100644
--- a/vivified/code/vivi_code_label.c
+++ b/vivified/code/vivi_code_label.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_label.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeLabel, vivi_code_label, VIVI_TYPE_CODE_STATEMENT)
 
@@ -35,12 +36,14 @@ vivi_code_label_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_label_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_label_to_code (ViviCodeToken *token)
+static void
+vivi_code_label_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeLabel *label = VIVI_CODE_LABEL (token);
 
-  return g_strdup_printf ("%s:\n", label->name);
+  vivi_code_printer_new_line (printer, TRUE);
+  vivi_code_printer_print (printer, label->name);
+  vivi_code_printer_print (printer, ":");
 }
 
 static void
@@ -51,7 +54,7 @@ vivi_code_label_class_init (ViviCodeLabelClass *klass)
 
   object_class->dispose = vivi_code_label_dispose;
 
-  token_class->to_code = vivi_code_label_to_code;
+  token_class->print = vivi_code_label_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_printer.c b/vivified/code/vivi_code_printer.c
new file mode 100644
index 0000000..33ff64b
--- /dev/null
+++ b/vivified/code/vivi_code_printer.c
@@ -0,0 +1,133 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_printer.h"
+
+G_DEFINE_ABSTRACT_TYPE (ViviCodePrinter, vivi_code_printer, G_TYPE_OBJECT)
+
+static void
+vivi_code_printer_dispose (GObject *object)
+{
+  //ViviCodePrinter *dec = VIVI_CODE_VAULE (object);
+
+  G_OBJECT_CLASS (vivi_code_printer_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_printer_class_init (ViviCodePrinterClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_code_printer_dispose;
+}
+
+static void
+vivi_code_printer_init (ViviCodePrinter *printer)
+{
+}
+
+void
+vivi_code_printer_print_token (ViviCodePrinter *printer, ViviCodeToken *token)
+{
+  ViviCodePrinterClass *klass;
+  ViviCodeTokenClass *token_class;
+
+  g_return_if_fail (VIVI_IS_CODE_PRINTER (printer));
+  g_return_if_fail (VIVI_IS_CODE_TOKEN (token));
+
+  klass = VIVI_CODE_PRINTER_GET_CLASS (printer);
+  if (klass->push_token)
+    klass->push_token (printer, token);
+  token_class = VIVI_CODE_TOKEN_GET_CLASS (token);
+  g_return_if_fail (token_class->print);
+  token_class->print (token, printer);
+  if (klass->pop_token)
+    klass->pop_token (printer, token);
+}
+
+void
+vivi_code_printer_print (ViviCodePrinter *printer, const char *text)
+{
+  ViviCodePrinterClass *klass;
+
+  g_return_if_fail (VIVI_IS_CODE_PRINTER (printer));
+  g_return_if_fail (text != NULL);
+
+  klass = VIVI_CODE_PRINTER_GET_CLASS (printer);
+  g_return_if_fail (klass->print);
+  klass->print (printer, text);
+}
+
+void
+vivi_code_printer_print_value (ViviCodePrinter *printer, ViviCodeValue *value,
+    ViviPrecedence precedence)
+{
+  gboolean needs_parens;
+
+  g_return_if_fail (VIVI_IS_CODE_PRINTER (printer));
+  g_return_if_fail (VIVI_IS_CODE_VALUE (value));
+
+  needs_parens = vivi_code_value_get_precedence (value) < precedence;
+  if (needs_parens)
+    vivi_code_printer_print (printer, "(");
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (value));
+  if (needs_parens)
+    vivi_code_printer_print (printer, ")");
+}
+
+void
+vivi_code_printer_new_line (ViviCodePrinter *printer, gboolean ignore_indentation)
+{
+  ViviCodePrinterClass *klass;
+
+  g_return_if_fail (VIVI_IS_CODE_PRINTER (printer));
+
+  klass = VIVI_CODE_PRINTER_GET_CLASS (printer);
+  if (klass->new_line)
+    klass->new_line (printer, ignore_indentation);
+}
+
+void
+vivi_code_printer_push_indentation (ViviCodePrinter *printer)
+{
+  g_return_if_fail (VIVI_IS_CODE_PRINTER (printer));
+
+  printer->indentation++;
+}
+
+void
+vivi_code_printer_pop_indentation (ViviCodePrinter *printer)
+{
+  g_return_if_fail (VIVI_IS_CODE_PRINTER (printer));
+  g_return_if_fail (printer->indentation > 0);
+
+  printer->indentation--;
+}
+
+guint
+vivi_code_printer_get_indentation (ViviCodePrinter *printer)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_PRINTER (printer), 0);
+
+  return printer->indentation;
+}
diff --git a/vivified/code/vivi_code_printer.h b/vivified/code/vivi_code_printer.h
new file mode 100644
index 0000000..5e886f0
--- /dev/null
+++ b/vivified/code/vivi_code_printer.h
@@ -0,0 +1,82 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_PRINTER_H_
+#define _VIVI_CODE_PRINTER_H_
+
+#include <swfdec/swfdec.h>
+#include <vivified/code/vivi_code_token.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodePrinterClass ViviCodePrinterClass;
+
+#define VIVI_TYPE_CODE_PRINTER                    (vivi_code_printer_get_type())
+#define VIVI_IS_CODE_PRINTER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_PRINTER))
+#define VIVI_IS_CODE_PRINTER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_PRINTER))
+#define VIVI_CODE_PRINTER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_PRINTER, ViviCodePrinter))
+#define VIVI_CODE_PRINTER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_PRINTER, ViviCodePrinterClass))
+#define VIVI_CODE_PRINTER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_PRINTER, ViviCodePrinterClass))
+
+struct _ViviCodePrinter
+{
+  GObject		object;
+
+  guint			indentation;	/* amount of indetation */
+};
+
+struct _ViviCodePrinterClass
+{
+  GObjectClass		object_class;
+
+  void			(* push_token)			(ViviCodePrinter *	printer,
+							 ViviCodeToken *	token);
+  void			(* pop_token)			(ViviCodePrinter *	printer,
+							 ViviCodeToken *	token);
+  void			(* print)			(ViviCodePrinter *	printer,
+							 const char *		text);
+  void			(* new_line)			(ViviCodePrinter *	printer,
+							 gboolean		ignore_indentation);
+  void			(* push_indentation)		(ViviCodePrinter *	printer);
+  void			(* pop_indentation)		(ViviCodePrinter *	printer);
+};
+
+GType			vivi_code_printer_get_type   	(void);
+
+void			vivi_code_printer_print_token	(ViviCodePrinter *	printer,
+							 ViviCodeToken *	token);
+void			vivi_code_printer_print_value	(ViviCodePrinter *	printer,
+							 ViviCodeValue *	value,
+							 ViviPrecedence		precedence);
+
+void			vivi_code_printer_print		(ViviCodePrinter *	printer,
+							 const char *		text);
+void			vivi_code_printer_new_line	(ViviCodePrinter *	printer,
+							 gboolean		ignore_indentation);
+void			vivi_code_printer_push_indentation
+							(ViviCodePrinter *	printer);
+void			vivi_code_printer_pop_indentation
+							(ViviCodePrinter *	printer);
+guint			vivi_code_printer_get_indentation
+							(ViviCodePrinter *	printer);
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_return.c b/vivified/code/vivi_code_return.c
index 84740cc..e2f0dfa 100644
--- a/vivified/code/vivi_code_return.c
+++ b/vivified/code/vivi_code_return.c
@@ -22,13 +22,15 @@
 #endif
 
 #include "vivi_code_return.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeReturn, vivi_code_return, VIVI_TYPE_CODE_STATEMENT)
 
-static char *
-vivi_code_return_to_code (ViviCodeToken *token)
+static void
+vivi_code_return_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
-  return g_strdup_printf ("  return;\n");
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_print (printer, "return;");
 }
 
 static void
@@ -36,7 +38,7 @@ vivi_code_return_class_init (ViviCodeReturnClass *klass)
 {
   ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
 
-  token_class->to_code = vivi_code_return_to_code;
+  token_class->print = vivi_code_return_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_text_printer.c b/vivified/code/vivi_code_text_printer.c
new file mode 100644
index 0000000..cc1b5b8
--- /dev/null
+++ b/vivified/code/vivi_code_text_printer.c
@@ -0,0 +1,72 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_text_printer.h"
+
+G_DEFINE_TYPE (ViviCodeTextPrinter, vivi_code_text_printer, VIVI_TYPE_CODE_PRINTER)
+
+static void
+vivi_code_text_printer_dispose (GObject *object)
+{
+  //ViviCodeTextPrinter *dec = VIVI_CODE_VAULE (object);
+
+  G_OBJECT_CLASS (vivi_code_text_printer_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_text_printer_print (ViviCodePrinter *printer, const char *text)
+{
+  g_print ("%s", text);
+}
+
+static void
+vivi_code_text_printer_new_line (ViviCodePrinter *printer, gboolean ignore_indentation)
+{
+  g_print ("\n");
+  if (!ignore_indentation)
+    g_print ("%*s", vivi_code_printer_get_indentation (printer) * 2, "");
+}
+
+static void
+vivi_code_text_printer_class_init (ViviCodeTextPrinterClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodePrinterClass *printer_class = VIVI_CODE_PRINTER_CLASS (klass);
+
+  object_class->dispose = vivi_code_text_printer_dispose;
+
+  printer_class->print = vivi_code_text_printer_print;
+  printer_class->new_line = vivi_code_text_printer_new_line;
+}
+
+static void
+vivi_code_text_printer_init (ViviCodeTextPrinter *text_printer)
+{
+}
+
+ViviCodePrinter *
+vivi_code_text_printer_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_TEXT_PRINTER, NULL);
+}
+
diff --git a/vivified/code/vivi_code_text_printer.h b/vivified/code/vivi_code_text_printer.h
new file mode 100644
index 0000000..d8b05c9
--- /dev/null
+++ b/vivified/code/vivi_code_text_printer.h
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_TEXT_PRINTER_H_
+#define _VIVI_CODE_TEXT_PRINTER_H_
+
+#include <vivified/code/vivi_code_printer.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeTextPrinter ViviCodeTextPrinter;
+typedef struct _ViviCodeTextPrinterClass ViviCodeTextPrinterClass;
+
+#define VIVI_TYPE_CODE_TEXT_PRINTER                    (vivi_code_text_printer_get_type())
+#define VIVI_IS_CODE_TEXT_PRINTER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_TEXT_PRINTER))
+#define VIVI_IS_CODE_TEXT_PRINTER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_TEXT_PRINTER))
+#define VIVI_CODE_TEXT_PRINTER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_TEXT_PRINTER, ViviCodeTextPrinter))
+#define VIVI_CODE_TEXT_PRINTER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_TEXT_PRINTER, ViviCodeTextPrinterClass))
+#define VIVI_CODE_TEXT_PRINTER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_TEXT_PRINTER, ViviCodeTextPrinterClass))
+
+struct _ViviCodeTextPrinter
+{
+  ViviCodePrinter	printer;
+};
+
+struct _ViviCodeTextPrinterClass
+{
+  ViviCodePrinterClass	printer_class;
+};
+
+GType			vivi_code_text_printer_get_type   	(void);
+
+ViviCodePrinter *	vivi_code_text_printer_new		(void);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_token.c b/vivified/code/vivi_code_token.c
index 17c56d0..e722aa8 100644
--- a/vivified/code/vivi_code_token.c
+++ b/vivified/code/vivi_code_token.c
@@ -46,16 +46,3 @@ vivi_code_token_init (ViviCodeToken *token)
 {
 }
 
-char *
-vivi_code_token_to_code (ViviCodeToken *token)
-{
-  ViviCodeTokenClass *klass;
-
-  g_return_val_if_fail (VIVI_IS_CODE_TOKEN (token), NULL);
-
-  klass = VIVI_CODE_TOKEN_GET_CLASS (token);
-  g_return_val_if_fail (klass->to_code != NULL, NULL);
-
-  return klass->to_code (token);
-}
-
diff --git a/vivified/code/vivi_code_token.h b/vivified/code/vivi_code_token.h
index b99950f..afdee1a 100644
--- a/vivified/code/vivi_code_token.h
+++ b/vivified/code/vivi_code_token.h
@@ -25,6 +25,8 @@
 G_BEGIN_DECLS
 
 
+typedef struct _ViviCodePrinter ViviCodePrinter;
+
 typedef struct _ViviCodeToken ViviCodeToken;
 typedef struct _ViviCodeTokenClass ViviCodeTokenClass;
 
@@ -44,13 +46,12 @@ struct _ViviCodeTokenClass
 {
   GObjectClass		object_class;
 
-  char *		(* to_code)			(ViviCodeToken *	token);
+  void			(* print)			(ViviCodeToken *	token,
+							 ViviCodePrinter *	printer);
 };
 
 GType			vivi_code_token_get_type   	(void);
 
-char *			vivi_code_token_to_code		(ViviCodeToken *	token);
-
 
 G_END_DECLS
 #endif
diff --git a/vivified/code/vivi_code_trace.c b/vivified/code/vivi_code_trace.c
index a4c17a4..efbe6d9 100644
--- a/vivified/code/vivi_code_trace.c
+++ b/vivified/code/vivi_code_trace.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_trace.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeTrace, vivi_code_trace, VIVI_TYPE_CODE_STATEMENT)
 
@@ -35,17 +36,15 @@ vivi_code_trace_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_trace_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_trace_to_code (ViviCodeToken *token)
+static void
+vivi_code_trace_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeTrace *trace = VIVI_CODE_TRACE (token);
-  char *s, *ret;
-
-  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (trace->value));
-  ret = g_strdup_printf ("  trace (%s);\n", s);
-  g_free (s);
 
-  return ret;
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_print (printer, "trace (");
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (trace->value));
+  vivi_code_printer_print (printer, ");");
 }
 
 static void
@@ -56,7 +55,7 @@ vivi_code_trace_class_init (ViviCodeTraceClass *klass)
 
   object_class->dispose = vivi_code_trace_dispose;
 
-  token_class->to_code = vivi_code_trace_to_code;
+  token_class->print = vivi_code_trace_print;
 }
 
 static void
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
index eb3561d..4c86ea1 100644
--- a/vivified/code/vivi_code_unary.c
+++ b/vivified/code/vivi_code_unary.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_unary.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeUnary, vivi_code_unary, VIVI_TYPE_CODE_VALUE)
 
@@ -35,20 +36,18 @@ vivi_code_unary_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_unary_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_unary_to_code (ViviCodeToken *token)
+static void
+vivi_code_unary_print (ViviCodeToken *token, ViviCodePrinter*printer)
 {
   ViviCodeUnary *unary = VIVI_CODE_UNARY (token);
-  char *s, *ret;
+  char *sign;
 
-  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (unary->value));
-  if (vivi_code_value_get_precedence (unary->value) < VIVI_PRECEDENCE_UNARY)
-    ret = g_strdup_printf ("%c(%s)", unary->operation, s);
-  else
-    ret = g_strdup_printf ("%c%s", unary->operation, s);
-  g_free (s);
+  /* FIXME: ugly! */
+  sign = g_strndup (&unary->operation, 1);
+  vivi_code_printer_print (printer, sign);
+  g_free (sign);
 
-  return ret;
+  vivi_code_printer_print_value (printer, unary->value, VIVI_PRECEDENCE_UNARY);
 }
 
 static gboolean
@@ -66,7 +65,7 @@ vivi_code_unary_class_init (ViviCodeUnaryClass *klass)
 
   object_class->dispose = vivi_code_unary_dispose;
 
-  token_class->to_code = vivi_code_unary_to_code;
+  token_class->print = vivi_code_unary_print;
 
   value_class->is_constant = vivi_code_unary_is_constant;
 }
diff --git a/vivified/code/vivi_code_value_statement.c b/vivified/code/vivi_code_value_statement.c
index 7340498..4a432c5 100644
--- a/vivified/code/vivi_code_value_statement.c
+++ b/vivified/code/vivi_code_value_statement.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "vivi_code_value_statement.h"
+#include "vivi_code_printer.h"
 
 G_DEFINE_TYPE (ViviCodeValueStatement, vivi_code_value_statement, VIVI_TYPE_CODE_STATEMENT)
 
@@ -35,17 +36,14 @@ vivi_code_value_statement_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_code_value_statement_parent_class)->dispose (object);
 }
 
-static char *
-vivi_code_value_statement_to_code (ViviCodeToken *token)
+static void
+vivi_code_value_statement_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
   ViviCodeValueStatement *stmt = VIVI_CODE_VALUE_STATEMENT (token);
-  char *s, *ret;
-
-  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->value));
-  ret = g_strdup_printf ("  %s;\n", s);
-  g_free (s);
 
-  return ret;
+  vivi_code_printer_new_line (printer, FALSE);
+  vivi_code_printer_print_token (printer, VIVI_CODE_TOKEN (stmt->value));
+  vivi_code_printer_print (printer, ";");
 }
 
 static void
@@ -56,7 +54,7 @@ vivi_code_value_statement_class_init (ViviCodeValueStatementClass *klass)
 
   object_class->dispose = vivi_code_value_statement_dispose;
 
-  token_class->to_code = vivi_code_value_statement_to_code;
+  token_class->print = vivi_code_value_statement_print;
 }
 
 static void
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
index 3a43770..c7f0178 100644
--- a/vivified/code/vivi_decompiler_block.c
+++ b/vivified/code/vivi_decompiler_block.c
@@ -43,10 +43,10 @@ vivi_decompiler_block_dispose (GObject *object)
   G_OBJECT_CLASS (vivi_decompiler_block_parent_class)->dispose (object);
 }
 
-static char *
-vivi_decompiler_block_to_code (ViviCodeToken *token)
+static void
+vivi_decompiler_block_print (ViviCodeToken *token, ViviCodePrinter *printer)
 {
-  g_return_val_if_reached (NULL);
+  g_return_if_reached ();
 }
 
 static void
@@ -57,7 +57,7 @@ vivi_decompiler_block_class_init (ViviDecompilerBlockClass *klass)
 
   object_class->dispose = vivi_decompiler_block_dispose;
 
-  token_class->to_code = vivi_decompiler_block_to_code;
+  token_class->print = vivi_decompiler_block_print;
 }
 
 static void
commit fd25875c37d30a5ee0b45a750d1ca15e642da1b1
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue Mar 18 22:53:45 2008 +0100

    rewrite this thing again - we now keep an AST
    
    Doesn't yet indent lines correctly

diff --git a/configure.ac b/configure.ac
index 40b055a..a3e186b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -356,8 +356,8 @@ test/trace/Makefile
 test/various/Makefile
 tools/Makefile
 vivified/Makefile
-vivified/compiler/Makefile
-vivified/compiler/test/Makefile
+vivified/code/Makefile
+vivified/code/test/Makefile
 vivified/core/Makefile
 vivified/dock/Makefile
 vivified/ui/Makefile
diff --git a/vivified/Makefile.am b/vivified/Makefile.am
index d231bea..94d8f7e 100644
--- a/vivified/Makefile.am
+++ b/vivified/Makefile.am
@@ -1 +1 @@
-SUBDIRS = compiler core dock ui
+SUBDIRS = code core dock ui
diff --git a/vivified/code/.gitignore b/vivified/code/.gitignore
new file mode 100644
index 0000000..8761c5f
--- /dev/null
+++ b/vivified/code/.gitignore
@@ -0,0 +1,14 @@
+*~
+CVS
+.cvsignore
+.deps
+.libs
+
+Makefile
+Makefile.in
+*.o
+*.la
+*.lo
+*.loT
+
+vivi-decompile
diff --git a/vivified/code/Makefile.am b/vivified/code/Makefile.am
new file mode 100644
index 0000000..4e339d0
--- /dev/null
+++ b/vivified/code/Makefile.am
@@ -0,0 +1,55 @@
+SUBDIRS = test
+
+noinst_LTLIBRARIES = libvivified-compiler.la
+
+libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
+
+libvivified_compiler_la_SOURCES = \
+	vivi_code_block.c \
+	vivi_code_comment.c \
+	vivi_code_constant.c \
+	vivi_code_get_url.c \
+	vivi_code_goto.c \
+	vivi_code_if.c \
+	vivi_code_label.c \
+	vivi_code_return.c \
+	vivi_code_statement.c \
+	vivi_code_token.c \
+	vivi_code_trace.c \
+	vivi_code_unary.c \
+	vivi_code_value.c \
+	vivi_code_value_statement.c \
+	vivi_decompiler_block.c \
+	vivi_decompiler_state.c \
+	vivi_decompiler.c
+
+noinst_HEADERS = \
+	vivi_code_block.h \
+	vivi_code_comment.h \
+	vivi_code_constant.h \
+	vivi_code_get_url.h \
+	vivi_code_goto.h \
+	vivi_code_if.h \
+	vivi_code_label.h \
+	vivi_code_return.h \
+	vivi_code_statement.h \
+	vivi_code_token.h \
+	vivi_code_trace.h \
+	vivi_code_unary.h \
+	vivi_code_value.h \
+	vivi_code_value_statement.h \
+	vivi_decompiler.h \
+	vivi_decompiler_block.h \
+	vivi_decompiler_state.h
+	vivified-compiler.h
+
+
+noinst_PROGRAMS = vivi-decompile
+
+vivi_decompile_SOURCES = \
+	decompiler.c
+
+vivi_decompile_CFLAGS =  $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+vivi_decompile_LDFLAGS = $(SWFDEC_LIBS)
+vivi_decompile_LDADD = libvivified-compiler.la
diff --git a/vivified/code/decompiler.c b/vivified/code/decompiler.c
new file mode 100644
index 0000000..e5927f2
--- /dev/null
+++ b/vivified/code/decompiler.c
@@ -0,0 +1,84 @@
+/* Swfdec
+ * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <swfdec/swfdec.h>
+
+#include <swfdec/swfdec_player_internal.h>
+#include <swfdec/swfdec_resource.h>
+#include <swfdec/swfdec_script_internal.h>
+#include <swfdec/swfdec_sprite_movie.h>
+#include <swfdec/swfdec_swf_decoder.h>
+
+#include "vivi_decompiler.h"
+
+static void
+decode_script (gpointer offset, gpointer scriptp, gpointer unused)
+{
+  SwfdecScript *script = scriptp;
+  ViviDecompiler *dec = vivi_decompiler_new (scriptp);
+  ViviCodeToken *token;
+  char *s;
+
+  g_print ("/* %s */\n", script->name);
+  token = VIVI_CODE_TOKEN (vivi_decompiler_get_block (dec));
+  s = vivi_code_token_to_code (token);
+  g_print ("%s\n", s);
+  g_free (s);
+  g_object_unref (dec);
+}
+
+int 
+main (int argc, char *argv[])
+{
+  SwfdecPlayer *player;
+  SwfdecSwfDecoder *dec;
+  SwfdecURL *url;
+
+  if (argc < 2) {
+    g_print ("%s FILENAME\n", argv[0]);
+    return 1;
+  }
+
+  player = swfdec_player_new (NULL);
+  url = swfdec_url_new_from_input (argv[1]);
+  swfdec_player_set_url (player, url);
+  swfdec_url_free (url);
+  /* FIXME: HACK! */
+  swfdec_player_advance (player, 0);
+  if (player->priv->roots == NULL ||
+      !SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data) ||
+      (dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder)) == NULL) {
+    g_printerr ("Error parsing file \"%s\"\n", argv[1]);
+    g_object_unref (player);
+    player = NULL;
+    return 1;
+  }
+
+  g_print ("/* version: %d - size: %ux%u */\n", dec->version,
+      player->priv->width, player->priv->height);
+  g_print ("\n");
+  g_hash_table_foreach (dec->scripts, decode_script, NULL);
+
+  g_object_unref (player);
+  return 0;
+}
+
diff --git a/vivified/code/test/Makefile.am b/vivified/code/test/Makefile.am
new file mode 100644
index 0000000..735dbd9
--- /dev/null
+++ b/vivified/code/test/Makefile.am
@@ -0,0 +1,18 @@
+check-local: ../vivi-decompile
+	RESULT=0; \
+	for file in $(srcdir)/*.swf; do \
+	  ../vivi-decompile $$file | diff -u - $$file.expect || RESULT=1; \
+	done; \
+	exit $$RESULT
+
+EXTRA_DIST = \
+	hello-world.as \
+	hello-world.swf \
+	hello-world.swf.trace \
+	if.as \
+	if.swf \
+	if.swf.expect \
+	if-nested.as \
+	if-nested.swf \
+	if-nested.swf.expect
+
diff --git a/vivified/code/test/hello-world.as b/vivified/code/test/hello-world.as
new file mode 100644
index 0000000..27c08da
--- /dev/null
+++ b/vivified/code/test/hello-world.as
@@ -0,0 +1,5 @@
+// makeswf -v 7 -s 200x150 -r 1 -o hello-world.swf hello-world.as
+
+trace ("Hello World!");
+
+loadMovie ("fscommand:quit", "");
diff --git a/vivified/code/test/hello-world.swf b/vivified/code/test/hello-world.swf
new file mode 100644
index 0000000..18039af
Binary files /dev/null and b/vivified/code/test/hello-world.swf differ
diff --git a/vivified/code/test/hello-world.swf.expect b/vivified/code/test/hello-world.swf.expect
new file mode 100644
index 0000000..bdda181
--- /dev/null
+++ b/vivified/code/test/hello-world.swf.expect
@@ -0,0 +1,8 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  trace ("Hello World!");
+  loadMovie ("fscommand:quit", "");
+}
+
diff --git a/vivified/code/test/if-nested.as b/vivified/code/test/if-nested.as
new file mode 100644
index 0000000..13fe78c
--- /dev/null
+++ b/vivified/code/test/if-nested.as
@@ -0,0 +1,15 @@
+// makeswf -v 7 -s 200x150 -r 1 -o if-nested.swf if-nested.as
+
+if (1) {
+  if (2) {
+    trace ("one");
+  } else {
+    trace ("two");
+  }
+} else {
+  if (3) {
+    trace ("three");
+  } else {
+    trace ("four");
+  }
+}
diff --git a/vivified/code/test/if-nested.swf b/vivified/code/test/if-nested.swf
new file mode 100644
index 0000000..b5bd6db
Binary files /dev/null and b/vivified/code/test/if-nested.swf differ
diff --git a/vivified/code/test/if-nested.swf.expect b/vivified/code/test/if-nested.swf.expect
new file mode 100644
index 0000000..62e7138
--- /dev/null
+++ b/vivified/code/test/if-nested.swf.expect
@@ -0,0 +1,20 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  if (1)
+  {
+    if (2)
+      trace ("one");
+    else
+      trace ("two");
+  }
+  else
+  {
+    if (3)
+      trace ("three");
+    else
+      trace ("four");
+  }
+}
+
diff --git a/vivified/code/test/if.as b/vivified/code/test/if.as
new file mode 100644
index 0000000..2bc876d
--- /dev/null
+++ b/vivified/code/test/if.as
@@ -0,0 +1,17 @@
+// makeswf -v 7 -s 200x150 -r 1 -o if.swf if.as
+
+if (1) {
+  trace ("Hello World!");
+} else {
+  trace ("Goodbye cruel world");
+}
+
+if ("foo")
+  trace ("Hello World");
+
+if (true)
+  ;
+else
+  trace ("Goodbye cruel world");
+
+loadMovie ("fscommand:quit", "");
diff --git a/vivified/code/test/if.swf b/vivified/code/test/if.swf
new file mode 100644
index 0000000..21d77a5
Binary files /dev/null and b/vivified/code/test/if.swf differ
diff --git a/vivified/code/test/if.swf.expect b/vivified/code/test/if.swf.expect
new file mode 100644
index 0000000..80a3fd1
--- /dev/null
+++ b/vivified/code/test/if.swf.expect
@@ -0,0 +1,15 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  if (1)
+    trace ("Hello World!");
+  else
+    trace ("Goodbye cruel world");
+  if ("foo")
+    trace ("Hello World");
+  if (!true)
+    trace ("Goodbye cruel world");
+  loadMovie ("fscommand:quit", "");
+}
+
diff --git a/vivified/code/vivi_code_block.c b/vivified/code/vivi_code_block.c
new file mode 100644
index 0000000..c19a75d
--- /dev/null
+++ b/vivified/code/vivi_code_block.c
@@ -0,0 +1,103 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_code_block.h"
+#include "vivi_code_comment.h"
+#include "vivi_code_label.h"
+
+G_DEFINE_TYPE (ViviCodeBlock, vivi_code_block, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_block_dispose (GObject *object)
+{
+  ViviCodeBlock *block = VIVI_CODE_BLOCK (object);
+
+  g_queue_foreach (block->statements, (GFunc) g_object_unref, NULL);
+  g_queue_free (block->statements);
+
+  G_OBJECT_CLASS (vivi_code_block_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_block_to_code (ViviCodeToken *token)
+{
+  ViviCodeBlock *block = VIVI_CODE_BLOCK (token);
+  GString *string;
+  char *s;
+  guint length;
+  GList *walk;
+
+  length = g_queue_get_length (block->statements);
+  if (length == 0)
+    return g_strdup ("  ;");
+
+  string = g_string_new ("");
+  if (length > 1)
+    g_string_append (string, "{\n");
+  for (walk = g_queue_peek_head_link (block->statements); walk; walk = walk->next) {
+    s = vivi_code_token_to_code (walk->data);
+    g_string_append (string, s);
+    g_free (s);
+  }
+  if (length > 1)
+    g_string_append (string, "}\n");
+
+  return g_string_free (string, FALSE);
+}
+
+static void
+vivi_code_block_class_init (ViviCodeBlockClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_block_dispose;
+
+  token_class->to_code = vivi_code_block_to_code;
+}
+
+static void
+vivi_code_block_init (ViviCodeBlock *block)
+{
+  block->statements = g_queue_new ();
+}
+
+ViviCodeBlock *
+vivi_code_block_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_BLOCK, NULL);
+}
+
+void
+vivi_code_block_add_statement (ViviCodeBlock *block,
+    ViviCodeStatement *statement)
+{
+  g_return_if_fail (VIVI_IS_CODE_BLOCK (block));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+
+  g_queue_push_tail (block->statements, statement);
+}
+
diff --git a/vivified/code/vivi_code_block.h b/vivified/code/vivi_code_block.h
new file mode 100644
index 0000000..53b6d3e
--- /dev/null
+++ b/vivified/code/vivi_code_block.h
@@ -0,0 +1,59 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_BLOCK_H_
+#define _VIVI_CODE_BLOCK_H_
+
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeBlock ViviCodeBlock;
+typedef struct _ViviCodeBlockClass ViviCodeBlockClass;
+
+#define VIVI_TYPE_CODE_BLOCK                    (vivi_code_block_get_type())
+#define VIVI_IS_CODE_BLOCK(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_BLOCK))
+#define VIVI_IS_CODE_BLOCK_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_BLOCK))
+#define VIVI_CODE_BLOCK(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_BLOCK, ViviCodeBlock))
+#define VIVI_CODE_BLOCK_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_BLOCK, ViviCodeBlockClass))
+#define VIVI_CODE_BLOCK_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_BLOCK, ViviCodeBlockClass))
+
+struct _ViviCodeBlock
+{
+  ViviCodeStatement	statement;
+
+  GQueue *		statements;	/* ViviCodeStatements inside this block */
+};
+
+struct _ViviCodeBlockClass
+{
+  ViviCodeStatementClass statement_class;
+};
+
+GType			vivi_code_block_get_type		(void);
+
+ViviCodeBlock *		vivi_code_block_new			(void);
+
+void			vivi_code_block_add_statement   	(ViviCodeBlock *		block,
+								 ViviCodeStatement *		statement);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_comment.c b/vivified/code/vivi_code_comment.c
new file mode 100644
index 0000000..58ead10
--- /dev/null
+++ b/vivified/code/vivi_code_comment.c
@@ -0,0 +1,74 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_comment.h"
+
+G_DEFINE_TYPE (ViviCodeComment, vivi_code_comment, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_comment_dispose (GObject *object)
+{
+  ViviCodeComment *comment = VIVI_CODE_COMMENT (object);
+
+  g_free (comment->comment);
+
+  G_OBJECT_CLASS (vivi_code_comment_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_comment_to_code (ViviCodeToken *token)
+{
+  ViviCodeComment *comment = VIVI_CODE_COMMENT (token);
+
+  return g_strdup_printf ("/* %s */\n", comment->comment);
+}
+
+static void
+vivi_code_comment_class_init (ViviCodeCommentClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_comment_dispose;
+
+  token_class->to_code = vivi_code_comment_to_code;
+}
+
+static void
+vivi_code_comment_init (ViviCodeComment *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_comment_new (const char *comment)
+{
+  ViviCodeComment *ret;
+
+  g_return_val_if_fail (comment != NULL, NULL);
+
+  ret = g_object_new (VIVI_TYPE_CODE_COMMENT, NULL);
+  ret->comment = g_strdup (comment);
+
+  return VIVI_CODE_TOKEN (ret);
+}
+
diff --git a/vivified/code/vivi_code_comment.h b/vivified/code/vivi_code_comment.h
new file mode 100644
index 0000000..13a4394
--- /dev/null
+++ b/vivified/code/vivi_code_comment.h
@@ -0,0 +1,56 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_COMMENT_H_
+#define _VIVI_CODE_COMMENT_H_
+
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeComment ViviCodeComment;
+typedef struct _ViviCodeCommentClass ViviCodeCommentClass;
+
+#define VIVI_TYPE_CODE_COMMENT                    (vivi_code_comment_get_type())
+#define VIVI_IS_CODE_COMMENT(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_COMMENT))
+#define VIVI_IS_CODE_COMMENT_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_COMMENT))
+#define VIVI_CODE_COMMENT(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_COMMENT, ViviCodeComment))
+#define VIVI_CODE_COMMENT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_COMMENT, ViviCodeCommentClass))
+#define VIVI_CODE_COMMENT_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_COMMENT, ViviCodeCommentClass))
+
+struct _ViviCodeComment
+{
+  ViviCodeStatement	statement;
+
+  char *		comment;
+};
+
+struct _ViviCodeCommentClass
+{
+  ViviCodeStatementClass statement_class;
+};
+
+GType			vivi_code_comment_get_type   	(void);
+
+ViviCodeToken *		vivi_code_comment_new		(const char *		comment);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_constant.c b/vivified/code/vivi_code_constant.c
new file mode 100644
index 0000000..d7f4ad6
--- /dev/null
+++ b/vivified/code/vivi_code_constant.c
@@ -0,0 +1,90 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_constant.h"
+
+G_DEFINE_TYPE (ViviCodeConstant, vivi_code_constant, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_constant_dispose (GObject *object)
+{
+  ViviCodeConstant *constant = VIVI_CODE_CONSTANT (object);
+
+  g_free (constant->text);
+
+  G_OBJECT_CLASS (vivi_code_constant_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_constant_to_code (ViviCodeToken *token)
+{
+  ViviCodeConstant *constant = VIVI_CODE_CONSTANT (token);
+
+  return g_strdup (constant->text);
+}
+
+static gboolean
+vivi_code_constant_is_constant (ViviCodeValue *value)
+{
+  return TRUE;
+}
+
+static void
+vivi_code_constant_class_init (ViviCodeConstantClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_constant_dispose;
+
+  token_class->to_code = vivi_code_constant_to_code;
+
+  value_class->is_constant = vivi_code_constant_is_constant;
+}
+
+static void
+vivi_code_constant_init (ViviCodeConstant *constant)
+{
+  vivi_code_value_set_precedence (VIVI_CODE_VALUE (constant), VIVI_PRECEDENCE_MAX);
+}
+
+ViviCodeToken *
+vivi_code_constant_new (const char *text)
+{
+  ViviCodeConstant *constant;
+
+  g_return_val_if_fail (text != NULL, NULL);
+
+  constant = g_object_new (VIVI_TYPE_CODE_CONSTANT, NULL);
+  constant->text = g_strdup (text);
+
+  return VIVI_CODE_TOKEN (constant);
+}
+
+ViviCodeToken *
+vivi_code_constant_new_undefined (void)
+{
+  return vivi_code_constant_new ("undefined");
+}
+
diff --git a/vivified/code/vivi_code_constant.h b/vivified/code/vivi_code_constant.h
new file mode 100644
index 0000000..72fa113
--- /dev/null
+++ b/vivified/code/vivi_code_constant.h
@@ -0,0 +1,57 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_CONSTANT_H_
+#define _VIVI_CODE_CONSTANT_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeConstant ViviCodeConstant;
+typedef struct _ViviCodeConstantClass ViviCodeConstantClass;
+
+#define VIVI_TYPE_CODE_CONSTANT                    (vivi_code_constant_get_type())
+#define VIVI_IS_CODE_CONSTANT(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_CONSTANT))
+#define VIVI_IS_CODE_CONSTANT_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_CONSTANT))
+#define VIVI_CODE_CONSTANT(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_CONSTANT, ViviCodeConstant))
+#define VIVI_CODE_CONSTANT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_CONSTANT, ViviCodeConstantClass))
+#define VIVI_CODE_CONSTANT_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_CONSTANT, ViviCodeConstantClass))
+
+struct _ViviCodeConstant
+{
+  ViviCodeValue		value;
+
+  char *		text;
+};
+
+struct _ViviCodeConstantClass
+{
+  ViviCodeValueClass  	value_class;
+};
+
+GType			vivi_code_constant_get_type   	(void);
+
+ViviCodeToken *		vivi_code_constant_new		(const char *	text);
+ViviCodeToken *		vivi_code_constant_new_undefined(void);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_get_url.c b/vivified/code/vivi_code_get_url.c
new file mode 100644
index 0000000..0791769
--- /dev/null
+++ b/vivified/code/vivi_code_get_url.c
@@ -0,0 +1,102 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_get_url.h"
+
+G_DEFINE_TYPE (ViviCodeGetUrl, vivi_code_get_url, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_get_url_dispose (GObject *object)
+{
+  ViviCodeGetUrl *get_url = VIVI_CODE_GET_URL (object);
+
+  g_object_unref (get_url->target);
+  g_object_unref (get_url->url);
+
+  G_OBJECT_CLASS (vivi_code_get_url_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_get_url_to_code (ViviCodeToken *token)
+{
+  ViviCodeGetUrl *url = VIVI_CODE_GET_URL (token);
+  char *t, *u, *ret;
+  const char *name;
+
+  if (url->variables) {
+    name = "loadVariables";
+  } else if (url->internal) {
+    name = "loadMovie";
+  } else {
+    name = "getURL";
+  }
+  u = vivi_code_token_to_code (VIVI_CODE_TOKEN (url->url));
+  t = vivi_code_token_to_code (VIVI_CODE_TOKEN (url->target));
+  if (url->method == 0) {
+    ret = g_strdup_printf ("%s (%s, %s);\n", name, u, t);
+  } else {
+    ret = g_strdup_printf ("%s (%s, %s, %s);\n", name, u, t,
+	url->method == 2 ? "\"POST\"" : "\"GET\"");
+  }
+  g_free (t);
+  g_free (u);
+
+  return ret;
+}
+
+static void
+vivi_code_get_url_class_init (ViviCodeGetUrlClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_get_url_dispose;
+
+  token_class->to_code = vivi_code_get_url_to_code;
+}
+
+static void
+vivi_code_get_url_init (ViviCodeGetUrl *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_get_url_new (ViviCodeValue *target, ViviCodeValue *url,
+    SwfdecLoaderRequest method, gboolean internal, gboolean variables)
+{
+  ViviCodeGetUrl *ret;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (target), NULL);
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (url), NULL);
+  g_return_val_if_fail (method < 4, NULL);
+
+  ret = g_object_new (VIVI_TYPE_CODE_GET_URL, NULL);
+  ret->target = target;
+  ret->url = url;
+  ret->method = method;
+  ret->internal = internal;
+  ret->variables = variables;
+
+  return VIVI_CODE_TOKEN (ret);
+}
+
diff --git a/vivified/code/vivi_code_get_url.h b/vivified/code/vivi_code_get_url.h
new file mode 100644
index 0000000..fb7e38c
--- /dev/null
+++ b/vivified/code/vivi_code_get_url.h
@@ -0,0 +1,65 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_GET_URL_H_
+#define _VIVI_CODE_GET_URL_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeGetUrl ViviCodeGetUrl;
+typedef struct _ViviCodeGetUrlClass ViviCodeGetUrlClass;
+
+#define VIVI_TYPE_CODE_GET_URL                    (vivi_code_get_url_get_type())
+#define VIVI_IS_CODE_GET_URL(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_GET_URL))
+#define VIVI_IS_CODE_GET_URL_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_GET_URL))
+#define VIVI_CODE_GET_URL(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_GET_URL, ViviCodeGetUrl))
+#define VIVI_CODE_GET_URL_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_GET_URL, ViviCodeGetUrlClass))
+#define VIVI_CODE_GET_URL_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_GET_URL, ViviCodeGetUrlClass))
+
+struct _ViviCodeGetUrl
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeValue *	url;
+  ViviCodeValue *	target;
+  SwfdecLoaderRequest	method;
+  gboolean		internal;
+  gboolean		variables;
+};
+
+struct _ViviCodeGetUrlClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_get_url_get_type   	(void);
+
+ViviCodeToken *		vivi_code_get_url_new		(ViviCodeValue *	target,
+							 ViviCodeValue *	url,
+							 SwfdecLoaderRequest	method,
+							 gboolean		internal,
+							 gboolean		variables);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_goto.c b/vivified/code/vivi_code_goto.c
new file mode 100644
index 0000000..e92b7f7
--- /dev/null
+++ b/vivified/code/vivi_code_goto.c
@@ -0,0 +1,74 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_goto.h"
+
+G_DEFINE_TYPE (ViviCodeGoto, vivi_code_goto, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_goto_dispose (GObject *object)
+{
+  ViviCodeGoto *gotoo = VIVI_CODE_GOTO (object);
+
+  g_object_unref (gotoo->label);
+
+  G_OBJECT_CLASS (vivi_code_goto_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_goto_to_code (ViviCodeToken *token)
+{
+  ViviCodeGoto *gotoo = VIVI_CODE_GOTO (token);
+
+  return g_strdup_printf ("  goto %s;\n", vivi_code_label_get_name (gotoo->label));
+}
+
+static void
+vivi_code_goto_class_init (ViviCodeGotoClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_goto_dispose;
+
+  token_class->to_code = vivi_code_goto_to_code;
+}
+
+static void
+vivi_code_goto_init (ViviCodeGoto *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_goto_new (ViviCodeLabel *label)
+{
+  ViviCodeGoto *gotoo;
+
+  g_return_val_if_fail (VIVI_IS_CODE_LABEL (label), NULL);
+
+  gotoo = g_object_new (VIVI_TYPE_CODE_GOTO, NULL);
+  gotoo->label = g_object_ref (label);
+
+  return VIVI_CODE_TOKEN (gotoo);
+}
+
diff --git a/vivified/code/vivi_code_goto.h b/vivified/code/vivi_code_goto.h
new file mode 100644
index 0000000..b220600
--- /dev/null
+++ b/vivified/code/vivi_code_goto.h
@@ -0,0 +1,57 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_GOTO_H_
+#define _VIVI_CODE_GOTO_H_
+
+#include <vivified/code/vivi_code_label.h>
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeGoto ViviCodeGoto;
+typedef struct _ViviCodeGotoClass ViviCodeGotoClass;
+
+#define VIVI_TYPE_CODE_GOTO                    (vivi_code_goto_get_type())
+#define VIVI_IS_CODE_GOTO(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_GOTO))
+#define VIVI_IS_CODE_GOTO_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_GOTO))
+#define VIVI_CODE_GOTO(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_GOTO, ViviCodeGoto))
+#define VIVI_CODE_GOTO_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_GOTO, ViviCodeGotoClass))
+#define VIVI_CODE_GOTO_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_GOTO, ViviCodeGotoClass))
+
+struct _ViviCodeGoto
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeLabel *	label;
+};
+
+struct _ViviCodeGotoClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_goto_get_type   	(void);
+
+ViviCodeToken *		vivi_code_goto_new		(ViviCodeLabel *	label);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_if.c b/vivified/code/vivi_code_if.c
new file mode 100644
index 0000000..3c5bc97
--- /dev/null
+++ b/vivified/code/vivi_code_if.c
@@ -0,0 +1,120 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_if.h"
+
+G_DEFINE_TYPE (ViviCodeIf, vivi_code_if, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_if_dispose (GObject *object)
+{
+  ViviCodeIf *stmt = VIVI_CODE_IF (object);
+
+  g_object_unref (stmt->condition);
+  if (stmt->if_statement)
+    g_object_unref (stmt->if_statement);
+  if (stmt->else_statement)
+    g_object_unref (stmt->else_statement);
+
+  G_OBJECT_CLASS (vivi_code_if_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_if_to_code (ViviCodeToken *token)
+{
+  ViviCodeIf *stmt = VIVI_CODE_IF (token);
+  GString *string;
+  char *s;
+
+  string = g_string_new ("");
+  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->condition));
+  g_string_append_printf (string, "if (%s)\n", s);
+  g_free (s);
+  if (stmt->if_statement) {
+    s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->if_statement));
+    g_string_append (string, s);
+    g_free (s);
+  } else {
+    g_string_append (string, "  ;\n");
+  }
+  if (stmt->else_statement) {
+    g_string_append (string, "else");
+    s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->else_statement));
+    g_string_append (string, s);
+    g_free (s);
+  }
+
+  return g_string_free (string, FALSE);
+}
+
+static void
+vivi_code_if_class_init (ViviCodeIfClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_if_dispose;
+
+  token_class->to_code = vivi_code_if_to_code;
+}
+
+static void
+vivi_code_if_init (ViviCodeIf *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_if_new (ViviCodeValue *condition)
+{
+  ViviCodeIf *stmt;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (condition), NULL);
+
+  stmt = g_object_new (VIVI_TYPE_CODE_IF, NULL);
+  stmt->condition = condition;
+
+  return VIVI_CODE_TOKEN (stmt);
+}
+
+void
+vivi_code_if_set_if (ViviCodeIf *if_stmt, ViviCodeStatement *statement)
+{
+  g_return_if_fail (VIVI_IS_CODE_IF (if_stmt));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+
+  if (if_stmt->if_statement)
+    g_object_unref (if_stmt->if_statement);
+  if_stmt->if_statement = statement;
+}
+
+void
+vivi_code_if_set_else (ViviCodeIf *if_stmt, ViviCodeStatement *statement)
+{
+  g_return_if_fail (VIVI_IS_CODE_IF (if_stmt));
+  g_return_if_fail (VIVI_IS_CODE_STATEMENT (statement));
+
+  if (if_stmt->else_statement)
+    g_object_unref (if_stmt->else_statement);
+  if_stmt->else_statement = statement;
+}
+
diff --git a/vivified/code/vivi_code_if.h b/vivified/code/vivi_code_if.h
new file mode 100644
index 0000000..aba0b40
--- /dev/null
+++ b/vivified/code/vivi_code_if.h
@@ -0,0 +1,63 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_IF_H_
+#define _VIVI_CODE_IF_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeIf ViviCodeIf;
+typedef struct _ViviCodeIfClass ViviCodeIfClass;
+
+#define VIVI_TYPE_CODE_IF                    (vivi_code_if_get_type())
+#define VIVI_IS_CODE_IF(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_IF))
+#define VIVI_IS_CODE_IF_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_IF))
+#define VIVI_CODE_IF(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_IF, ViviCodeIf))
+#define VIVI_CODE_IF_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_IF, ViviCodeIfClass))
+#define VIVI_CODE_IF_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_IF, ViviCodeIfClass))
+
+struct _ViviCodeIf
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeValue *	condition;
+  ViviCodeStatement *	if_statement;
+  ViviCodeStatement *	else_statement;
+};
+
+struct _ViviCodeIfClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_if_get_type   	(void);
+
+ViviCodeToken *		vivi_code_if_new		(ViviCodeValue *	condition);
+void			vivi_code_if_set_if		(ViviCodeIf *		if_stmt,
+							 ViviCodeStatement *	statement);
+void		  	vivi_code_if_set_else		(ViviCodeIf *		if_stmt,
+							 ViviCodeStatement *	statement);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_label.c b/vivified/code/vivi_code_label.c
new file mode 100644
index 0000000..d860ce3
--- /dev/null
+++ b/vivified/code/vivi_code_label.c
@@ -0,0 +1,82 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_label.h"
+
+G_DEFINE_TYPE (ViviCodeLabel, vivi_code_label, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_label_dispose (GObject *object)
+{
+  ViviCodeLabel *label = VIVI_CODE_LABEL (object);
+
+  g_free (label->name);
+
+  G_OBJECT_CLASS (vivi_code_label_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_label_to_code (ViviCodeToken *token)
+{
+  ViviCodeLabel *label = VIVI_CODE_LABEL (token);
+
+  return g_strdup_printf ("%s:\n", label->name);
+}
+
+static void
+vivi_code_label_class_init (ViviCodeLabelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_label_dispose;
+
+  token_class->to_code = vivi_code_label_to_code;
+}
+
+static void
+vivi_code_label_init (ViviCodeLabel *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_label_new (const char *name)
+{
+  ViviCodeLabel *label;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  label = g_object_new (VIVI_TYPE_CODE_LABEL, NULL);
+  label->name = g_strdup (name);
+
+  return VIVI_CODE_TOKEN (label);
+}
+
+const char *
+vivi_code_label_get_name (ViviCodeLabel *label)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_LABEL (label), NULL);
+
+  return label->name;
+}
+
diff --git a/vivified/code/vivi_code_label.h b/vivified/code/vivi_code_label.h
new file mode 100644
index 0000000..f79dc04
--- /dev/null
+++ b/vivified/code/vivi_code_label.h
@@ -0,0 +1,58 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_LABEL_H_
+#define _VIVI_CODE_LABEL_H_
+
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeLabel ViviCodeLabel;
+typedef struct _ViviCodeLabelClass ViviCodeLabelClass;
+
+#define VIVI_TYPE_CODE_LABEL                    (vivi_code_label_get_type())
+#define VIVI_IS_CODE_LABEL(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_LABEL))
+#define VIVI_IS_CODE_LABEL_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_LABEL))
+#define VIVI_CODE_LABEL(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_LABEL, ViviCodeLabel))
+#define VIVI_CODE_LABEL_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_LABEL, ViviCodeLabelClass))
+#define VIVI_CODE_LABEL_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_LABEL, ViviCodeLabelClass))
+
+struct _ViviCodeLabel
+{
+  ViviCodeStatement	statement;
+
+  char *		name;
+};
+
+struct _ViviCodeLabelClass
+{
+  ViviCodeStatementClass statement_class;
+};
+
+GType			vivi_code_label_get_type   	(void);
+
+ViviCodeToken *		vivi_code_label_new		(const char *		name);
+
+const char *		vivi_code_label_get_name	(ViviCodeLabel *	label);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_return.c b/vivified/code/vivi_code_return.c
new file mode 100644
index 0000000..84740cc
--- /dev/null
+++ b/vivified/code/vivi_code_return.c
@@ -0,0 +1,52 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_return.h"
+
+G_DEFINE_TYPE (ViviCodeReturn, vivi_code_return, VIVI_TYPE_CODE_STATEMENT)
+
+static char *
+vivi_code_return_to_code (ViviCodeToken *token)
+{
+  return g_strdup_printf ("  return;\n");
+}
+
+static void
+vivi_code_return_class_init (ViviCodeReturnClass *klass)
+{
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  token_class->to_code = vivi_code_return_to_code;
+}
+
+static void
+vivi_code_return_init (ViviCodeReturn *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_return_new (void)
+{
+  return g_object_new (VIVI_TYPE_CODE_RETURN, NULL);
+}
+
diff --git a/vivified/code/vivi_code_return.h b/vivified/code/vivi_code_return.h
new file mode 100644
index 0000000..dda801e
--- /dev/null
+++ b/vivified/code/vivi_code_return.h
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_RETURN_H_
+#define _VIVI_CODE_RETURN_H_
+
+#include <vivified/code/vivi_code_statement.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeReturn ViviCodeReturn;
+typedef struct _ViviCodeReturnClass ViviCodeReturnClass;
+
+#define VIVI_TYPE_CODE_RETURN                    (vivi_code_return_get_type())
+#define VIVI_IS_CODE_RETURN(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_RETURN))
+#define VIVI_IS_CODE_RETURN_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_RETURN))
+#define VIVI_CODE_RETURN(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_RETURN, ViviCodeReturn))
+#define VIVI_CODE_RETURN_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_RETURN, ViviCodeReturnClass))
+#define VIVI_CODE_RETURN_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_RETURN, ViviCodeReturnClass))
+
+struct _ViviCodeReturn
+{
+  ViviCodeStatement	statement;
+};
+
+struct _ViviCodeReturnClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_return_get_type   	(void);
+
+ViviCodeToken *		vivi_code_return_new		(void);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_statement.c b/vivified/code/vivi_code_statement.c
new file mode 100644
index 0000000..1a3b76e
--- /dev/null
+++ b/vivified/code/vivi_code_statement.c
@@ -0,0 +1,48 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_statement.h"
+
+G_DEFINE_ABSTRACT_TYPE (ViviCodeStatement, vivi_code_statement, VIVI_TYPE_CODE_TOKEN)
+
+static void
+vivi_code_statement_dispose (GObject *object)
+{
+  //ViviCodeStatement *statement = VIVI_CODE_STATEMENT (object);
+
+  G_OBJECT_CLASS (vivi_code_statement_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_statement_class_init (ViviCodeStatementClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_code_statement_dispose;
+}
+
+static void
+vivi_code_statement_init (ViviCodeStatement *token)
+{
+}
+
diff --git a/vivified/code/vivi_code_statement.h b/vivified/code/vivi_code_statement.h
new file mode 100644
index 0000000..9a4215a
--- /dev/null
+++ b/vivified/code/vivi_code_statement.h
@@ -0,0 +1,52 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_STATEMENT_H_
+#define _VIVI_CODE_STATEMENT_H_
+
+#include <vivified/code/vivi_code_token.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeStatement ViviCodeStatement;
+typedef struct _ViviCodeStatementClass ViviCodeStatementClass;
+
+#define VIVI_TYPE_CODE_STATEMENT                    (vivi_code_statement_get_type())
+#define VIVI_IS_CODE_STATEMENT(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_STATEMENT))
+#define VIVI_IS_CODE_STATEMENT_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_STATEMENT))
+#define VIVI_CODE_STATEMENT(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_STATEMENT, ViviCodeStatement))
+#define VIVI_CODE_STATEMENT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_STATEMENT, ViviCodeStatementClass))
+#define VIVI_CODE_STATEMENT_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_STATEMENT, ViviCodeStatementClass))
+
+struct _ViviCodeStatement
+{
+  ViviCodeToken		token;
+};
+
+struct _ViviCodeStatementClass
+{
+  ViviCodeTokenClass	token_class;
+};
+
+GType			vivi_code_statement_get_type   	(void);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_token.c b/vivified/code/vivi_code_token.c
new file mode 100644
index 0000000..17c56d0
--- /dev/null
+++ b/vivified/code/vivi_code_token.c
@@ -0,0 +1,61 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_token.h"
+
+G_DEFINE_ABSTRACT_TYPE (ViviCodeToken, vivi_code_token, G_TYPE_OBJECT)
+
+static void
+vivi_code_token_dispose (GObject *object)
+{
+  //ViviCodeToken *dec = VIVI_CODE_VAULE (object);
+
+  G_OBJECT_CLASS (vivi_code_token_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_token_class_init (ViviCodeTokenClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_code_token_dispose;
+}
+
+static void
+vivi_code_token_init (ViviCodeToken *token)
+{
+}
+
+char *
+vivi_code_token_to_code (ViviCodeToken *token)
+{
+  ViviCodeTokenClass *klass;
+
+  g_return_val_if_fail (VIVI_IS_CODE_TOKEN (token), NULL);
+
+  klass = VIVI_CODE_TOKEN_GET_CLASS (token);
+  g_return_val_if_fail (klass->to_code != NULL, NULL);
+
+  return klass->to_code (token);
+}
+
diff --git a/vivified/code/vivi_code_token.h b/vivified/code/vivi_code_token.h
new file mode 100644
index 0000000..b99950f
--- /dev/null
+++ b/vivified/code/vivi_code_token.h
@@ -0,0 +1,56 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_TOKEN_H_
+#define _VIVI_CODE_TOKEN_H_
+
+#include <swfdec/swfdec.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeToken ViviCodeToken;
+typedef struct _ViviCodeTokenClass ViviCodeTokenClass;
+
+#define VIVI_TYPE_CODE_TOKEN                    (vivi_code_token_get_type())
+#define VIVI_IS_CODE_TOKEN(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_TOKEN))
+#define VIVI_IS_CODE_TOKEN_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_TOKEN))
+#define VIVI_CODE_TOKEN(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_TOKEN, ViviCodeToken))
+#define VIVI_CODE_TOKEN_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_TOKEN, ViviCodeTokenClass))
+#define VIVI_CODE_TOKEN_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_TOKEN, ViviCodeTokenClass))
+
+struct _ViviCodeToken
+{
+  GObject		object;
+};
+
+struct _ViviCodeTokenClass
+{
+  GObjectClass		object_class;
+
+  char *		(* to_code)			(ViviCodeToken *	token);
+};
+
+GType			vivi_code_token_get_type   	(void);
+
+char *			vivi_code_token_to_code		(ViviCodeToken *	token);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_trace.c b/vivified/code/vivi_code_trace.c
new file mode 100644
index 0000000..a4c17a4
--- /dev/null
+++ b/vivified/code/vivi_code_trace.c
@@ -0,0 +1,79 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_trace.h"
+
+G_DEFINE_TYPE (ViviCodeTrace, vivi_code_trace, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_trace_dispose (GObject *object)
+{
+  ViviCodeTrace *trace = VIVI_CODE_TRACE (object);
+
+  g_object_unref (trace->value);
+
+  G_OBJECT_CLASS (vivi_code_trace_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_trace_to_code (ViviCodeToken *token)
+{
+  ViviCodeTrace *trace = VIVI_CODE_TRACE (token);
+  char *s, *ret;
+
+  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (trace->value));
+  ret = g_strdup_printf ("  trace (%s);\n", s);
+  g_free (s);
+
+  return ret;
+}
+
+static void
+vivi_code_trace_class_init (ViviCodeTraceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_trace_dispose;
+
+  token_class->to_code = vivi_code_trace_to_code;
+}
+
+static void
+vivi_code_trace_init (ViviCodeTrace *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_trace_new (ViviCodeValue *value)
+{
+  ViviCodeTrace *trace;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  trace = g_object_new (VIVI_TYPE_CODE_TRACE, NULL);
+  trace->value = value;
+
+  return VIVI_CODE_TOKEN (trace);
+}
+
diff --git a/vivified/code/vivi_code_trace.h b/vivified/code/vivi_code_trace.h
new file mode 100644
index 0000000..3ce8c37
--- /dev/null
+++ b/vivified/code/vivi_code_trace.h
@@ -0,0 +1,57 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_TRACE_H_
+#define _VIVI_CODE_TRACE_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeTrace ViviCodeTrace;
+typedef struct _ViviCodeTraceClass ViviCodeTraceClass;
+
+#define VIVI_TYPE_CODE_TRACE                    (vivi_code_trace_get_type())
+#define VIVI_IS_CODE_TRACE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_TRACE))
+#define VIVI_IS_CODE_TRACE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_TRACE))
+#define VIVI_CODE_TRACE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_TRACE, ViviCodeTrace))
+#define VIVI_CODE_TRACE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_TRACE, ViviCodeTraceClass))
+#define VIVI_CODE_TRACE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_TRACE, ViviCodeTraceClass))
+
+struct _ViviCodeTrace
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeValue *	value;
+};
+
+struct _ViviCodeTraceClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_trace_get_type   	(void);
+
+ViviCodeToken *		vivi_code_trace_new		(ViviCodeValue *	value);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_unary.c b/vivified/code/vivi_code_unary.c
new file mode 100644
index 0000000..eb3561d
--- /dev/null
+++ b/vivified/code/vivi_code_unary.c
@@ -0,0 +1,95 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_unary.h"
+
+G_DEFINE_TYPE (ViviCodeUnary, vivi_code_unary, VIVI_TYPE_CODE_VALUE)
+
+static void
+vivi_code_unary_dispose (GObject *object)
+{
+  ViviCodeUnary *unary = VIVI_CODE_UNARY (object);
+
+  g_object_unref (unary->value);
+
+  G_OBJECT_CLASS (vivi_code_unary_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_unary_to_code (ViviCodeToken *token)
+{
+  ViviCodeUnary *unary = VIVI_CODE_UNARY (token);
+  char *s, *ret;
+
+  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (unary->value));
+  if (vivi_code_value_get_precedence (unary->value) < VIVI_PRECEDENCE_UNARY)
+    ret = g_strdup_printf ("%c(%s)", unary->operation, s);
+  else
+    ret = g_strdup_printf ("%c%s", unary->operation, s);
+  g_free (s);
+
+  return ret;
+}
+
+static gboolean
+vivi_code_unary_is_constant (ViviCodeValue *value)
+{
+  return vivi_code_value_is_constant (VIVI_CODE_UNARY (value)->value);
+}
+
+static void
+vivi_code_unary_class_init (ViviCodeUnaryClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+  ViviCodeValueClass *value_class = VIVI_CODE_VALUE_CLASS (klass);
+
+  object_class->dispose = vivi_code_unary_dispose;
+
+  token_class->to_code = vivi_code_unary_to_code;
+
+  value_class->is_constant = vivi_code_unary_is_constant;
+}
+
+static void
+vivi_code_unary_init (ViviCodeUnary *unary)
+{
+  ViviCodeValue *value = VIVI_CODE_VALUE (unary);
+
+  vivi_code_value_set_precedence (value, VIVI_PRECEDENCE_UNARY);
+}
+
+ViviCodeToken *
+vivi_code_unary_new (ViviCodeValue *value, char operation)
+{
+  ViviCodeUnary *unary;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  unary = g_object_new (VIVI_TYPE_CODE_UNARY, NULL);
+  unary->value = value;
+  unary->operation = operation;
+
+  return VIVI_CODE_TOKEN (unary);
+}
+
diff --git a/vivified/code/vivi_code_unary.h b/vivified/code/vivi_code_unary.h
new file mode 100644
index 0000000..45e060e
--- /dev/null
+++ b/vivified/code/vivi_code_unary.h
@@ -0,0 +1,59 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_UNARY_H_
+#define _VIVI_CODE_UNARY_H_
+
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeUnary ViviCodeUnary;
+typedef struct _ViviCodeUnaryClass ViviCodeUnaryClass;
+
+#define VIVI_TYPE_CODE_UNARY                    (vivi_code_unary_get_type())
+#define VIVI_IS_CODE_UNARY(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_UNARY))
+#define VIVI_IS_CODE_UNARY_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_UNARY))
+#define VIVI_CODE_UNARY(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_UNARY, ViviCodeUnary))
+#define VIVI_CODE_UNARY_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_UNARY, ViviCodeUnaryClass))
+#define VIVI_CODE_UNARY_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_UNARY, ViviCodeUnaryClass))
+
+struct _ViviCodeUnary
+{
+  ViviCodeValue		parent;
+
+  char			operation;
+  ViviCodeValue *	value;
+};
+
+struct _ViviCodeUnaryClass
+{
+  ViviCodeValueClass	value_class;
+};
+
+GType			vivi_code_unary_get_type   	(void);
+
+ViviCodeToken *		vivi_code_unary_new		(ViviCodeValue *	value,
+							 char			operation);
+
+char			vivi_code_unary_get_operation	(ViviCodeUnary *	unary);
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_value.c b/vivified/code/vivi_code_value.c
new file mode 100644
index 0000000..99d4d5a
--- /dev/null
+++ b/vivified/code/vivi_code_value.c
@@ -0,0 +1,78 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_value.h"
+
+G_DEFINE_ABSTRACT_TYPE (ViviCodeValue, vivi_code_value, VIVI_TYPE_CODE_TOKEN)
+
+static void
+vivi_code_value_dispose (GObject *object)
+{
+  //ViviCodeValue *dec = VIVI_CODE_VAULE (object);
+
+  G_OBJECT_CLASS (vivi_code_value_parent_class)->dispose (object);
+}
+
+static void
+vivi_code_value_class_init (ViviCodeValueClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_code_value_dispose;
+}
+
+static void
+vivi_code_value_init (ViviCodeValue *value)
+{
+  value->precedence = VIVI_PRECEDENCE_MIN;
+}
+
+gboolean
+vivi_code_value_is_constant (ViviCodeValue *value)
+{
+  ViviCodeValueClass *klass;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), FALSE);
+
+  klass = VIVI_CODE_VALUE_GET_CLASS (value);
+  g_return_val_if_fail (klass->is_constant != NULL, FALSE);
+
+  return klass->is_constant (value);
+}
+
+void
+vivi_code_value_set_precedence (ViviCodeValue *value, ViviPrecedence precedence)
+{
+  g_return_if_fail (VIVI_IS_CODE_VALUE (value));
+
+  value->precedence = precedence;
+}
+
+ViviPrecedence
+vivi_code_value_get_precedence (ViviCodeValue *value)
+{
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), VIVI_PRECEDENCE_MIN);
+
+  return value->precedence;
+}
+
diff --git a/vivified/code/vivi_code_value.h b/vivified/code/vivi_code_value.h
new file mode 100644
index 0000000..6a8b9af
--- /dev/null
+++ b/vivified/code/vivi_code_value.h
@@ -0,0 +1,86 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_VALUE_H_
+#define _VIVI_CODE_VALUE_H_
+
+#include <vivified/code/vivi_code_token.h>
+
+G_BEGIN_DECLS
+
+
+typedef enum {
+  VIVI_PRECEDENCE_COMMA,
+  VIVI_PRECEDENCE_ASSIGNMENT,
+  VIVI_PRECEDENCE_CONDITIONAL,
+  VIVI_PRECEDENCE_OR,
+  VIVI_PRECEDENCE_AND,
+  VIVI_PRECEDENCE_BINARY_OR,
+  VIVI_PRECEDENCE_BINARY_XOR,
+  VIVI_PRECEDENCE_BINARY_AND,
+  VIVI_PRECEDENCE_EQUALITY,
+  VIVI_PRECEDENCE_RELATIONAL,
+  VIVI_PRECEDENCE_SHIFT,
+  VIVI_PRECEDENCE_ADD,
+  VIVI_PRECEDENCE_MULTIPLY,
+  VIVI_PRECEDENCE_UNARY,
+  VIVI_PRECEDENCE_INCREMENT,
+  VIVI_PRECEDENCE_CALL,
+  VIVI_PRECEDENCE_MEMBER,
+  VIVI_PRECEDENCE_PARENTHESIS
+} ViviPrecedence;
+
+#define VIVI_PRECEDENCE_MIN VIVI_PRECEDENCE_COMMA
+#define VIVI_PRECEDENCE_MAX VIVI_PRECEDENCE_PARENTHESIS
+
+typedef struct _ViviCodeValue ViviCodeValue;
+typedef struct _ViviCodeValueClass ViviCodeValueClass;
+
+#define VIVI_TYPE_CODE_VALUE                    (vivi_code_value_get_type())
+#define VIVI_IS_CODE_VALUE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_VALUE))
+#define VIVI_IS_CODE_VALUE_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_VALUE))
+#define VIVI_CODE_VALUE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_VALUE, ViviCodeValue))
+#define VIVI_CODE_VALUE_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_VALUE, ViviCodeValueClass))
+#define VIVI_CODE_VALUE_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_VALUE, ViviCodeValueClass))
+
+struct _ViviCodeValue
+{
+  ViviCodeToken		token;
+
+  ViviPrecedence	precedence;
+};
+
+struct _ViviCodeValueClass
+{
+  ViviCodeTokenClass  	token_class;
+
+  gboolean		(* is_constant)			(ViviCodeValue *	value);
+};
+
+GType			vivi_code_value_get_type   	(void);
+
+gboolean		vivi_code_value_is_constant	(ViviCodeValue *	value);
+
+void			vivi_code_value_set_precedence	(ViviCodeValue *	value,
+							 ViviPrecedence		precedence);
+ViviPrecedence		vivi_code_value_get_precedence	(ViviCodeValue *	value);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_code_value_statement.c b/vivified/code/vivi_code_value_statement.c
new file mode 100644
index 0000000..7340498
--- /dev/null
+++ b/vivified/code/vivi_code_value_statement.c
@@ -0,0 +1,79 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_code_value_statement.h"
+
+G_DEFINE_TYPE (ViviCodeValueStatement, vivi_code_value_statement, VIVI_TYPE_CODE_STATEMENT)
+
+static void
+vivi_code_value_statement_dispose (GObject *object)
+{
+  ViviCodeValueStatement *stmt = VIVI_CODE_VALUE_STATEMENT (object);
+
+  g_object_unref (stmt->value);
+
+  G_OBJECT_CLASS (vivi_code_value_statement_parent_class)->dispose (object);
+}
+
+static char *
+vivi_code_value_statement_to_code (ViviCodeToken *token)
+{
+  ViviCodeValueStatement *stmt = VIVI_CODE_VALUE_STATEMENT (token);
+  char *s, *ret;
+
+  s = vivi_code_token_to_code (VIVI_CODE_TOKEN (stmt->value));
+  ret = g_strdup_printf ("  %s;\n", s);
+  g_free (s);
+
+  return ret;
+}
+
+static void
+vivi_code_value_statement_class_init (ViviCodeValueStatementClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_code_value_statement_dispose;
+
+  token_class->to_code = vivi_code_value_statement_to_code;
+}
+
+static void
+vivi_code_value_statement_init (ViviCodeValueStatement *token)
+{
+}
+
+ViviCodeToken *
+vivi_code_value_statement_new (ViviCodeValue *value)
+{
+  ViviCodeValueStatement *stmt;
+
+  g_return_val_if_fail (VIVI_IS_CODE_VALUE (value), NULL);
+
+  stmt = g_object_new (VIVI_TYPE_CODE_VALUE_STATEMENT, NULL);
+  stmt->value = value;
+
+  return VIVI_CODE_TOKEN (stmt);
+}
+
diff --git a/vivified/code/vivi_code_value_statement.h b/vivified/code/vivi_code_value_statement.h
new file mode 100644
index 0000000..c506878
--- /dev/null
+++ b/vivified/code/vivi_code_value_statement.h
@@ -0,0 +1,56 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_CODE_VALUE_STATEMENT_H_
+#define _VIVI_CODE_VALUE_STATEMENT_H_
+
+#include <vivified/code/vivi_code_statement.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviCodeValueStatement ViviCodeValueStatement;
+typedef struct _ViviCodeValueStatementClass ViviCodeValueStatementClass;
+
+#define VIVI_TYPE_CODE_VALUE_STATEMENT                    (vivi_code_value_statement_get_type())
+#define VIVI_IS_CODE_VALUE_STATEMENT(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_CODE_VALUE_STATEMENT))
+#define VIVI_IS_CODE_VALUE_STATEMENT_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_CODE_VALUE_STATEMENT))
+#define VIVI_CODE_VALUE_STATEMENT(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_CODE_VALUE_STATEMENT, ViviCodeValueStatement))
+#define VIVI_CODE_VALUE_STATEMENT_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_CODE_VALUE_STATEMENT, ViviCodeValueStatementClass))
+#define VIVI_CODE_VALUE_STATEMENT_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_CODE_VALUE_STATEMENT, ViviCodeValueStatementClass))
+
+struct _ViviCodeValueStatement
+{
+  ViviCodeStatement	statement;
+
+  ViviCodeValue *	value;
+};
+
+struct _ViviCodeValueStatementClass
+{
+  ViviCodeStatementClass	statement_class;
+};
+
+GType			vivi_code_value_statement_get_type   	(void);
+
+ViviCodeToken *		vivi_code_value_statement_new		(ViviCodeValue *	value);
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler.c b/vivified/code/vivi_decompiler.c
new file mode 100644
index 0000000..3944ded
--- /dev/null
+++ b/vivified/code/vivi_decompiler.c
@@ -0,0 +1,702 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <swfdec/swfdec_as_interpret.h>
+#include <swfdec/swfdec_bits.h>
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_decompiler.h"
+#include "vivi_code_constant.h"
+#include "vivi_code_get_url.h"
+#include "vivi_code_if.h"
+#include "vivi_code_return.h"
+#include "vivi_code_trace.h"
+#include "vivi_code_unary.h"
+#include "vivi_code_value_statement.h"
+#include "vivi_decompiler_block.h"
+#include "vivi_decompiler_state.h"
+
+#if 0
+static G_GNUC_UNUSED void
+DUMP_BLOCKS (ViviDecompiler *dec)
+{
+  GList *walk;
+
+  g_print ("dumping blocks:\n");
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    ViviDecompilerBlock *block = walk->data;
+    g_print ("  %p -> %p\n", block->start->pc, block->exitpc);
+  }
+}
+#else
+#define DUMP_BLOCKS(dec) (void) 0
+#endif
+
+static ViviDecompilerBlock *
+vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *state)
+{
+  ViviDecompilerBlock *block;
+  GList *walk;
+  const guint8 *pc, *block_start;
+
+  DUMP_BLOCKS (dec);
+  pc = vivi_decompiler_state_get_pc (state);
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    block = walk->data;
+    block_start = vivi_decompiler_block_get_start (block);
+    if (block_start < pc) {
+      if (vivi_decompiler_block_contains (block, pc)) {
+	vivi_decompiler_block_reset (block);
+	break;
+      }
+      continue;
+    }
+    if (block_start == pc) {
+      g_printerr ("FIXME: check that the blocks are equal\n");
+      vivi_decompiler_state_free (state);
+      return block;
+    }
+    break;
+  }
+
+  /* FIXME: see if the block is already there! */
+  block = vivi_decompiler_block_new (state);
+  dec->blocks = g_list_insert_before (dec->blocks, walk ? walk->next : NULL, block);
+  return block;
+}
+
+/*** BYTECODE DECOMPILER ***/
+
+typedef gboolean (* DecompileFunc) (ViviDecompilerBlock *block, ViviDecompilerState *state,
+          guint code, const guint8 *data, guint len);
+
+static char *
+escape_string (const char *s)
+{
+  GString *str;
+  char *next;
+
+  str = g_string_new ("\"");
+  while ((next = strpbrk (s, "\"\n"))) {
+    g_string_append_len (str, s, next - s);
+    switch (*next) {
+      case '"':
+	g_string_append (str, "\"");
+	break;
+      case '\n':
+	g_string_append (str, "\n");
+	break;
+      default:
+	g_assert_not_reached ();
+    }
+    s = next + 1;
+  }
+  g_string_append (str, s);
+  g_string_append_c (str, '"');
+  return g_string_free (str, FALSE);
+}
+
+static gboolean
+vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *val;
+  SwfdecBits bits;
+  guint type;
+  char *value;
+
+  swfdec_bits_init_data (&bits, data, len);
+  while (swfdec_bits_left (&bits)) {
+    type = swfdec_bits_get_u8 (&bits);
+    switch (type) {
+      case 0: /* string */
+	{
+	  char *s = swfdec_bits_get_string (&bits, vivi_decompiler_state_get_version (state));
+	  if (s == NULL) {
+	    vivi_decompiler_block_add_error (block, "could not read string");
+	    return FALSE;
+	  }
+	  value = escape_string (s);
+	  g_free (s);
+	  break;
+	}
+      case 1: /* float */
+	value = g_strdup_printf ("%f", swfdec_bits_get_float (&bits));
+	break;
+      case 2: /* null */
+	value = g_strdup ("null");
+	break;
+      case 3: /* undefined */
+	break;
+      case 4: /* register */
+	{
+	  val = vivi_decompiler_state_get_register (
+		state, swfdec_bits_get_u8 (&bits));
+	  vivi_decompiler_state_push (state, g_object_ref (val));
+	  continue;
+	}
+      case 5: /* boolean */
+	value = g_strdup (swfdec_bits_get_u8 (&bits) ? "true" : "false");
+	break;
+      case 6: /* double */
+	value = g_strdup_printf ("%g", swfdec_bits_get_double (&bits));
+	break;
+      case 7: /* 32bit int */
+	value = g_strdup_printf ("%d", swfdec_bits_get_u32 (&bits));
+	break;
+      case 8: /* 8bit ConstantPool address */
+      case 9: /* 16bit ConstantPool address */
+	{
+	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
+	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
+	  if (pool == NULL) {
+	    vivi_decompiler_block_add_error (block, "no constant pool to push from");
+	    return FALSE;
+	  }
+	  if (i >= swfdec_constant_pool_size (pool)) {
+	    vivi_decompiler_block_add_error (block, "constant pool index %u too high - only %u elements",
+		i, swfdec_constant_pool_size (pool));
+	    return FALSE;
+	  }
+	  value = escape_string (swfdec_constant_pool_get (pool, i));
+	  break;
+	}
+      default:
+	vivi_decompiler_block_add_error (block, "Push: type %u not implemented", type);
+	return FALSE;
+    }
+    val = VIVI_CODE_VALUE (vivi_code_constant_new (value));
+    vivi_decompiler_state_push (state, val);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_pop (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeToken *stmt;
+  ViviCodeValue *val;
+  
+  val = vivi_decompiler_state_pop (state);
+  stmt = vivi_code_value_statement_new (val);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (stmt));
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_constant_pool (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  SwfdecConstantPool *pool = swfdec_constant_pool_new_from_action (data, len, 
+      vivi_decompiler_state_get_version (state));
+
+  vivi_decompiler_state_set_constant_pool (state, pool);
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_trace (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeToken *trace;
+  ViviCodeValue *val;
+  
+  val = vivi_decompiler_state_pop (state);
+  trace = vivi_code_trace_new (val);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (trace));
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_end (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  vivi_decompiler_block_finish (block, state);
+  return FALSE;
+}
+
+static gboolean
+vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *url, *target;
+
+  target = vivi_decompiler_state_pop (state);
+  url = vivi_decompiler_state_pop (state);
+
+  if (len != 1) {
+    vivi_decompiler_block_add_error (block, "invalid length in getURL2 command");   
+    g_object_unref (target);
+    g_object_unref (url);
+  } else {
+    ViviCodeToken *token;
+    guint method = data[0] & 3;
+    guint internal = data[0] & 64;
+    guint variables = data[0] & 128;
+
+    token = vivi_code_get_url_new (target, url, method, internal, variables);
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (token));
+  }
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviCodeValue *val;
+
+  val = vivi_decompiler_state_pop (state);
+  val = VIVI_CODE_VALUE (vivi_code_unary_new (val, '!'));
+  vivi_decompiler_state_push (state, val);
+  return TRUE;
+}
+
+static DecompileFunc decompile_funcs[256] = {
+  [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
+  [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
+  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
+  [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
+
+  [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
+  [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
+  [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
+  [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
+  [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
+};
+
+static gboolean
+vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block, 
+    ViviDecompilerState *state, guint code, const guint8 *data, guint len)
+{
+  gboolean result;
+
+  switch (code) {
+    case SWFDEC_AS_ACTION_IF:
+      {
+	ViviDecompilerBlock *next, *branch;
+	ViviCodeValue *val;
+	ViviDecompilerState *new;
+	gint16 offset;
+
+	if (len != 2) {
+	  vivi_decompiler_block_add_error (block, "If action length invalid (is %u, should be 2)", len);
+	  return FALSE;
+	}
+	offset = data[0] | (data[1] << 8);
+	vivi_decompiler_state_add_pc (state, 5);
+	val = vivi_decompiler_state_pop (state);
+	vivi_decompiler_block_finish (block, state);
+	new = vivi_decompiler_state_copy (state);
+	next = vivi_decompiler_push_block_for_state (dec, new);
+	new = vivi_decompiler_state_copy (state);
+	vivi_decompiler_state_add_pc (new, offset);
+	branch = vivi_decompiler_push_block_for_state (dec, new);
+	if (vivi_decompiler_block_is_finished (block)) {
+	  vivi_decompiler_block_set_next (block, next);
+	  vivi_decompiler_block_set_branch (block, branch, val);
+	} else {
+	  g_object_unref (val);
+	}
+      }
+      return FALSE;
+    case SWFDEC_AS_ACTION_JUMP:
+      {
+	ViviDecompilerBlock *next;
+	ViviDecompilerState *new;
+	gint16 offset;
+
+	if (len != 2) {
+	  vivi_decompiler_block_add_error (block, "Jump action length invalid (is %u, should be 2)", len);
+	  return FALSE;
+	}
+	offset = data[0] | (data[1] << 8);
+	vivi_decompiler_state_add_pc (state, 5);
+	vivi_decompiler_block_finish (block, state);
+	new = vivi_decompiler_state_copy (state);
+	vivi_decompiler_state_add_pc (new, offset);
+	next = vivi_decompiler_push_block_for_state (dec, new);
+	if (vivi_decompiler_block_is_finished (block)) {
+	  vivi_decompiler_block_set_next (block, next);
+	}
+      }
+      return FALSE;
+    default:
+      if (decompile_funcs[code]) {
+	result = decompile_funcs[code] (block, state, code, data, len);
+      } else {
+	vivi_decompiler_block_add_error (block, "unknown bytecode 0x%02X %u", code, code);
+	result = FALSE;
+      }
+      if (data)
+	vivi_decompiler_state_add_pc (state, 3 + len);
+      else
+	vivi_decompiler_state_add_pc (state, 1);
+      return result;
+  };
+
+  return TRUE;
+}
+
+static void
+vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block)
+{
+  ViviDecompilerState *state;
+  ViviDecompilerBlock *next_block;
+  GList *list;
+  const guint8 *pc, *start, *end, *exit;
+  const guint8 *data;
+  guint code, len;
+
+  start = dec->script->buffer->data;
+  end = start + dec->script->buffer->length;
+  state = vivi_decompiler_state_copy (vivi_decompiler_block_get_start_state (block));
+  exit = dec->script->exit;
+  list = g_list_find (dec->blocks, block);
+  if (list->next) {
+    next_block = list->next->data;
+    exit = vivi_decompiler_block_get_start (next_block);
+  } else {
+    next_block = NULL;
+  }
+
+  while ((pc = vivi_decompiler_state_get_pc (state)) != exit) {
+    if (pc < start || pc >= end) {
+      vivi_decompiler_block_add_error (block, "program counter out of range");
+      goto error;
+    }
+    code = pc[0];
+    if (code & 0x80) {
+      if (pc + 2 >= end) {
+	vivi_decompiler_block_add_error (block, "bytecode %u length value out of range", code);
+	goto error;
+      }
+      data = pc + 3;
+      len = pc[1] | pc[2] << 8;
+      if (data + len > end) {
+	vivi_decompiler_block_add_error (block, "bytecode %u length %u out of range", code, len);
+	goto error;
+      }
+    } else {
+      data = NULL;
+      len = 0;
+    }
+    if (!vivi_decompiler_process (dec, block, state, code, data, len))
+      goto out;
+  }
+  vivi_decompiler_block_finish (block, state);
+  if (next_block) {
+    vivi_decompiler_block_set_next (block, next_block);
+  }
+
+out:
+error:
+  vivi_decompiler_state_free (state);
+}
+
+/*** PROGRAM STRUCTURE ANALYSIS ***/
+
+static ViviDecompilerBlock *
+vivi_decompiler_find_start_block (ViviDecompiler *dec)
+{
+  GList *walk;
+  
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    ViviDecompilerBlock *block = walk->data;
+
+    if (vivi_decompiler_block_get_start (block) == dec->script->main)
+      return block;
+  }
+  g_assert_not_reached ();
+  return NULL;
+}
+
+static void
+vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
+{
+  ViviCodeBlock *block;
+  ViviDecompilerBlock *current, *next;
+  GList *ordered, *walk;
+
+  current = vivi_decompiler_find_start_block (dec);
+
+  ordered = NULL;
+  while (current) {
+    g_assert (g_list_find (dec->blocks, current));
+    dec->blocks = g_list_remove (dec->blocks, current);
+    ordered = g_list_prepend (ordered, current);
+    next = vivi_decompiler_block_get_branch (current);
+    if (next)
+      vivi_decompiler_block_force_label (next);
+    next = vivi_decompiler_block_get_next (current);
+    if (next == NULL || !g_list_find (dec->blocks, next)) {
+      if (next)
+	vivi_decompiler_block_force_label (next);
+      next = dec->blocks ? dec->blocks->data : NULL;
+    }
+    current = next;
+  }
+  g_assert (dec->blocks == NULL);
+  ordered = g_list_reverse (ordered);
+
+  block = VIVI_CODE_BLOCK (vivi_code_block_new ());
+  for (walk = ordered; walk; walk = walk->next) {
+    current = walk->data;
+    next = vivi_decompiler_block_get_next (current);
+    if (walk->next && next == walk->next->data)
+      vivi_decompiler_block_set_next (current, NULL);
+    vivi_decompiler_block_add_to_block (current, block);
+    if (next == NULL && walk->next != NULL)
+      vivi_code_block_add_statement (block, VIVI_CODE_STATEMENT (vivi_code_return_new ()));
+  }
+  g_list_foreach (ordered, (GFunc) g_object_unref, NULL);
+  g_list_free (ordered);
+  dec->blocks = g_list_prepend (dec->blocks, block);
+}
+
+static void
+vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
+{
+  g_assert (vivi_decompiler_block_get_n_incoming (block) == 0);
+  dec->blocks = g_list_remove (dec->blocks, block);
+  g_object_unref (block);
+}
+
+/*  ONE
+ *   |              ==>   BLOCK
+ *  TWO
+ */
+static gboolean
+vivi_decompiler_merge_lines (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block, *next;
+  ViviCodeValue *val;
+  gboolean result;
+  GList *walk;
+
+  result = FALSE;
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    block = walk->data;
+
+    /* This is an if block or so */
+    if (vivi_decompiler_block_get_branch (block) != NULL)
+      continue;
+    /* has no next block */
+    next = vivi_decompiler_block_get_next (block);
+    if (next == NULL)
+      continue;
+    /* The next block has multiple incoming blocks */
+    if (vivi_decompiler_block_get_n_incoming (next) != 1)
+      continue;
+
+    vivi_decompiler_block_add_to_block (next, VIVI_CODE_BLOCK (block));
+    vivi_decompiler_block_set_next (block, vivi_decompiler_block_get_next (next));
+    val = vivi_decompiler_block_get_branch_condition (next);
+    if (val) {
+      vivi_decompiler_block_set_branch (block, 
+	  vivi_decompiler_block_get_branch (next),
+	  g_object_ref (val));
+    }
+    vivi_decompiler_purge_block (dec, next);
+  }
+
+  return result;
+}
+
+/*     COND
+ *    /    \
+ *  [IF] [ELSE]     ==>   BLOCK
+ *    \    /
+ *     NEXT
+ */
+static gboolean
+vivi_decompiler_merge_if (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block, *if_block, *else_block;
+  ViviCodeIf *if_stmt;
+  gboolean result;
+  GList *walk;
+
+  result = FALSE;
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    block = walk->data;
+
+    if_block = vivi_decompiler_block_get_branch (block);
+    else_block = vivi_decompiler_block_get_next (block);
+    /* not an if block */
+    if (if_block == NULL)
+      continue;
+    /* one of the blocks doesn't exist */
+    if (if_block == vivi_decompiler_block_get_next (else_block)) 
+      if_block = NULL;
+    else if (else_block == vivi_decompiler_block_get_next (if_block))
+      else_block = NULL;
+    /* if in if in if in if... */
+    if ((else_block && vivi_decompiler_block_get_branch (else_block)) || 
+	(if_block && vivi_decompiler_block_get_branch (if_block)))
+      continue;
+    /* if other blocks reference the blocks, bail, there's loops involved */
+    if ((else_block && vivi_decompiler_block_get_n_incoming (else_block) > 1) ||
+	(if_block && vivi_decompiler_block_get_n_incoming (if_block) > 1))
+      continue;
+    /* if both blocks exist, they must have the same exit block */
+    if (if_block && else_block && 
+	vivi_decompiler_block_get_next (if_block) != vivi_decompiler_block_get_next (else_block))
+      continue;
+
+    /* FINALLY we can merge the blocks */
+    if_stmt = VIVI_CODE_IF (vivi_code_if_new (g_object_ref (
+	  vivi_decompiler_block_get_branch_condition (block))));
+    vivi_decompiler_block_set_branch (block, NULL, NULL);
+    vivi_decompiler_block_set_next (block, 
+	vivi_decompiler_block_get_next (if_block ? if_block : else_block));
+    if (if_block) {
+      ViviCodeBlock *tmp = vivi_code_block_new ();
+
+      vivi_decompiler_block_set_next (if_block, NULL);
+      vivi_decompiler_block_set_branch (if_block, NULL, NULL);
+      vivi_decompiler_block_add_to_block (if_block, tmp);
+      vivi_decompiler_purge_block (dec, if_block);
+      vivi_code_if_set_if (if_stmt, VIVI_CODE_STATEMENT (tmp));
+    }
+    if (else_block) {
+      ViviCodeBlock *tmp = vivi_code_block_new ();
+
+      vivi_decompiler_block_set_next (else_block, NULL);
+      vivi_decompiler_block_set_branch (else_block, NULL, NULL);
+      vivi_decompiler_block_add_to_block (else_block, tmp);
+      vivi_decompiler_purge_block (dec, else_block);
+      vivi_code_if_set_else (if_stmt, VIVI_CODE_STATEMENT (tmp));
+    }
+    vivi_code_block_add_statement (VIVI_CODE_BLOCK (block),
+	VIVI_CODE_STATEMENT (if_stmt));
+    result = TRUE;
+  }
+
+  return result;
+}
+
+static void
+vivi_decompiler_merge_blocks (ViviDecompiler *dec)
+{
+  gboolean restart;
+
+  DUMP_BLOCKS (dec);
+
+  do {
+    restart = FALSE;
+
+    restart |= vivi_decompiler_merge_lines (dec);
+    restart |= vivi_decompiler_merge_if (dec);
+  } while (restart);
+
+  DUMP_BLOCKS (dec);
+  vivi_decompiler_merge_blocks_last_resort (dec);
+}
+
+static void
+vivi_decompiler_run (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block;
+  ViviDecompilerState *state;
+  GList *walk;
+
+  state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
+  if (dec->script->constant_pool) {
+    vivi_decompiler_state_set_constant_pool (state,
+	swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
+	    dec->script->constant_pool->length, dec->script->version));
+  }
+  block = vivi_decompiler_block_new (state);
+  g_assert (dec->blocks == NULL);
+  dec->blocks = g_list_prepend (dec->blocks, block);
+  while (TRUE) {
+    for (walk = dec->blocks; walk; walk = walk->next) {
+      block = walk->data;
+      if (!vivi_decompiler_block_is_finished (block))
+	break;
+    }
+    if (walk == NULL)
+      break;
+    vivi_decompiler_block_decompile (dec, block);
+  }
+
+  vivi_decompiler_merge_blocks (dec);
+}
+
+/*** OBJECT ***/
+
+G_DEFINE_TYPE (ViviDecompiler, vivi_decompiler, G_TYPE_OBJECT)
+
+static void
+vivi_decompiler_dispose (GObject *object)
+{
+  ViviDecompiler *dec = VIVI_DECOMPILER (object);
+
+  if (dec->script) {
+    swfdec_script_unref (dec->script);
+    dec->script = NULL;
+  }
+  g_list_foreach (dec->blocks, (GFunc) g_object_unref, NULL);
+  g_list_free (dec->blocks);
+  dec->blocks = NULL;
+
+  G_OBJECT_CLASS (vivi_decompiler_parent_class)->dispose (object);
+}
+
+static void
+vivi_decompiler_class_init (ViviDecompilerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_decompiler_dispose;
+}
+
+static void
+vivi_decompiler_init (ViviDecompiler *dec)
+{
+}
+
+ViviDecompiler *
+vivi_decompiler_new (SwfdecScript *script)
+{
+  ViviDecompiler *dec = g_object_new (VIVI_TYPE_DECOMPILER, NULL);
+
+  dec->script = swfdec_script_ref (script);
+  vivi_decompiler_run (dec);
+
+  return dec;
+}
+
+ViviCodeBlock *
+vivi_decompiler_get_block (ViviDecompiler *dec)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
+
+  return dec->blocks->data;
+}
+
diff --git a/vivified/code/vivi_decompiler.h b/vivified/code/vivi_decompiler.h
new file mode 100644
index 0000000..ccb99fd
--- /dev/null
+++ b/vivified/code/vivi_decompiler.h
@@ -0,0 +1,58 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_H_
+#define _VIVI_DECOMPILER_H_
+
+#include <swfdec/swfdec.h>
+#include <vivified/code/vivi_code_block.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompiler ViviDecompiler;
+typedef struct _ViviDecompilerClass ViviDecompilerClass;
+
+#define VIVI_TYPE_DECOMPILER                    (vivi_decompiler_get_type())
+#define VIVI_IS_DECOMPILER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER))
+#define VIVI_IS_DECOMPILER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER))
+#define VIVI_DECOMPILER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER, ViviDecompiler))
+#define VIVI_DECOMPILER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
+#define VIVI_DECOMPILER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
+
+struct _ViviDecompiler
+{
+  SwfdecAsObject	object;
+
+  SwfdecScript *	script;		/* script that we decompile */
+  GList *		blocks;		/* list of all blocks in this script ordered by pc (should be one after decompilation is done) */
+};
+
+struct _ViviDecompilerClass
+{
+  SwfdecAsObjectClass	object_class;
+};
+
+GType			vivi_decompiler_get_type   	(void);
+
+ViviDecompiler *	vivi_decompiler_new		(SwfdecScript *		script);
+ViviCodeBlock *		vivi_decompiler_get_block	(ViviDecompiler *	dec);
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler_block.c b/vivified/code/vivi_decompiler_block.c
new file mode 100644
index 0000000..3a43770
--- /dev/null
+++ b/vivified/code/vivi_decompiler_block.c
@@ -0,0 +1,251 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_decompiler_block.h"
+#include "vivi_code_comment.h"
+#include "vivi_code_goto.h"
+#include "vivi_code_if.h"
+#include "vivi_code_label.h"
+
+G_DEFINE_TYPE (ViviDecompilerBlock, vivi_decompiler_block, VIVI_TYPE_CODE_BLOCK)
+
+static void
+vivi_decompiler_block_dispose (GObject *object)
+{
+  ViviDecompilerBlock *block = VIVI_DECOMPILER_BLOCK (object);
+
+  vivi_decompiler_block_reset (block);
+  vivi_decompiler_state_free (block->start);
+
+  G_OBJECT_CLASS (vivi_decompiler_block_parent_class)->dispose (object);
+}
+
+static char *
+vivi_decompiler_block_to_code (ViviCodeToken *token)
+{
+  g_return_val_if_reached (NULL);
+}
+
+static void
+vivi_decompiler_block_class_init (ViviDecompilerBlockClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ViviCodeTokenClass *token_class = VIVI_CODE_TOKEN_CLASS (klass);
+
+  object_class->dispose = vivi_decompiler_block_dispose;
+
+  token_class->to_code = vivi_decompiler_block_to_code;
+}
+
+static void
+vivi_decompiler_block_init (ViviDecompilerBlock *block)
+{
+}
+
+void
+vivi_decompiler_block_reset (ViviDecompilerBlock *block)
+{
+  g_queue_foreach (VIVI_CODE_BLOCK (block)->statements, (GFunc) g_object_unref, NULL);
+  g_queue_clear (VIVI_CODE_BLOCK (block)->statements);
+  vivi_decompiler_block_set_next (block, NULL);
+  vivi_decompiler_block_set_branch (block, NULL, NULL);
+  block->endpc = NULL;
+}
+
+ViviDecompilerBlock *
+vivi_decompiler_block_new (ViviDecompilerState *state)
+{
+  ViviDecompilerBlock *block;
+
+  g_return_val_if_fail (state != NULL, NULL);
+
+  block = g_object_new (VIVI_TYPE_DECOMPILER_BLOCK, NULL);
+  block->start = state;
+  block->startpc = vivi_decompiler_state_get_pc (state);
+
+  return block;
+}
+
+ViviCodeToken *
+vivi_decompiler_block_get_label (ViviDecompilerBlock *block)
+{
+  ViviCodeToken *token;
+
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_BLOCK (block), NULL);
+
+  token = g_queue_peek_head (VIVI_CODE_BLOCK (block)->statements);
+  if (!VIVI_IS_CODE_LABEL (token))
+    return NULL;
+
+  return token;
+}
+
+void
+vivi_decompiler_block_force_label (ViviDecompilerBlock *block)
+{
+  ViviCodeToken *token;
+  char *s;
+
+  g_return_if_fail (VIVI_IS_DECOMPILER_BLOCK (block));
+
+  if (vivi_decompiler_block_get_label (block))
+    return;
+
+  s = g_strdup_printf ("label_%p", block);
+  token = vivi_code_label_new (s);
+  g_free (s);
+  g_queue_push_head (VIVI_CODE_BLOCK (block)->statements, token);
+}
+
+void
+vivi_decompiler_block_set_next (ViviDecompilerBlock *block, ViviDecompilerBlock *next)
+{
+  if (block->next)
+    block->next->incoming--;
+  block->next = next;
+  if (next)
+    next->incoming++;
+}
+
+ViviDecompilerBlock *
+vivi_decompiler_block_get_next (ViviDecompilerBlock *block)
+{
+  return block->next;
+}
+
+void
+vivi_decompiler_block_set_branch (ViviDecompilerBlock *block, ViviDecompilerBlock *branch,
+    ViviCodeValue *branch_condition)
+{
+  g_return_if_fail ((branch != NULL) ^ (branch_condition == NULL));
+
+  if (block->branch) {
+    block->branch->incoming--;
+    g_object_unref (block->branch_condition);
+  }
+  block->branch = branch;
+  block->branch_condition = branch_condition;
+  if (branch)
+    branch->incoming++;
+}
+
+ViviDecompilerBlock *
+vivi_decompiler_block_get_branch (ViviDecompilerBlock *block)
+{
+  return block->branch;
+}
+
+ViviCodeValue *
+vivi_decompiler_block_get_branch_condition (ViviDecompilerBlock *block)
+{
+  return block->branch_condition;
+}
+
+void
+vivi_decompiler_block_add_error (ViviDecompilerBlock *block,
+    const char *format, ...)
+{
+  ViviCodeToken *token;
+  va_list varargs;
+  char *s;
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+
+  token = vivi_code_comment_new (s);
+  g_free (s);
+  vivi_code_block_add_statement (VIVI_CODE_BLOCK (block), VIVI_CODE_STATEMENT (token));
+}
+
+const guint8 *
+vivi_decompiler_block_get_start (ViviDecompilerBlock *block)
+{
+  return block->startpc;
+}
+
+gboolean
+vivi_decompiler_block_contains (ViviDecompilerBlock *block, const guint8 *pc)
+{
+  return pc >= block->startpc && pc < block->endpc;
+}
+
+void
+vivi_decompiler_block_finish (ViviDecompilerBlock *block, const ViviDecompilerState *state)
+{
+  g_return_if_fail (block->endpc == NULL);
+
+  block->endpc = vivi_decompiler_state_get_pc (state);
+}
+
+gboolean
+vivi_decompiler_block_is_finished (ViviDecompilerBlock *block)
+{
+  return block->endpc != NULL;
+}
+
+const ViviDecompilerState *
+vivi_decompiler_block_get_start_state (ViviDecompilerBlock *block)
+{
+  return block->start;
+}
+
+guint
+vivi_decompiler_block_get_n_incoming (ViviDecompilerBlock *block)
+{
+  return block->incoming;
+}
+
+void
+vivi_decompiler_block_add_to_block (ViviDecompilerBlock *block,
+    ViviCodeBlock *target)
+{
+  GList *walk;
+
+  g_return_if_fail (VIVI_IS_DECOMPILER_BLOCK (block));
+  g_return_if_fail (VIVI_IS_CODE_BLOCK (target));
+
+  for (walk = g_queue_peek_head_link (VIVI_CODE_BLOCK (block)->statements); 
+      walk; walk = walk->next) {
+    vivi_code_block_add_statement (target, g_object_ref (walk->data));
+  }
+  if (block->branch) {
+    ViviCodeToken *token = vivi_code_if_new (
+	g_object_ref (block->branch_condition));
+    vivi_decompiler_block_force_label (block->branch);
+    vivi_code_if_set_if (VIVI_CODE_IF (token), VIVI_CODE_STATEMENT (
+	  vivi_code_goto_new (g_object_ref (
+		vivi_decompiler_block_get_label (block->branch)))));
+    vivi_code_block_add_statement (target, VIVI_CODE_STATEMENT (token));
+  }
+  if (block->next) {
+    vivi_decompiler_block_force_label (block->next);
+    vivi_code_block_add_statement (target, VIVI_CODE_STATEMENT (
+	  vivi_code_goto_new (g_object_ref (
+	      vivi_decompiler_block_get_label (block->next)))));
+  }
+}
+
diff --git a/vivified/code/vivi_decompiler_block.h b/vivified/code/vivi_decompiler_block.h
new file mode 100644
index 0000000..bac0dfe
--- /dev/null
+++ b/vivified/code/vivi_decompiler_block.h
@@ -0,0 +1,93 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_BLOCK_H_
+#define _VIVI_DECOMPILER_BLOCK_H_
+
+#include <vivified/code/vivi_code_block.h>
+#include <vivified/code/vivi_decompiler_state.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompilerBlock ViviDecompilerBlock;
+typedef struct _ViviDecompilerBlockClass ViviDecompilerBlockClass;
+
+#define VIVI_TYPE_DECOMPILER_BLOCK                    (vivi_decompiler_block_get_type())
+#define VIVI_IS_DECOMPILER_BLOCK(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER_BLOCK))
+#define VIVI_IS_DECOMPILER_BLOCK_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER_BLOCK))
+#define VIVI_DECOMPILER_BLOCK(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER_BLOCK, ViviDecompilerBlock))
+#define VIVI_DECOMPILER_BLOCK_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER_BLOCK, ViviDecompilerBlockClass))
+#define VIVI_DECOMPILER_BLOCK_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER_BLOCK, ViviDecompilerBlockClass))
+
+struct _ViviDecompilerBlock
+{
+  ViviCodeBlock		block;
+
+  ViviDecompilerState *	start;		/* starting state */
+  guint			incoming;	/* number of incoming blocks */
+  const guint8 *	startpc;	/* pointer to first command in block */
+  /* set by parsing the block */
+  const guint8 *	endpc;		/* pointer to after last parsed command or NULL if not parsed yet */
+  ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
+  ViviDecompilerBlock *	branch;		/* NULL or block branched to i if statement */
+  ViviCodeValue *	branch_condition;/* NULL or value for deciding if a branch should be taken */
+};
+
+struct _ViviDecompilerBlockClass
+{
+  ViviCodeBlockClass	block_class;
+};
+
+GType			vivi_decompiler_block_get_type   	(void);
+
+ViviDecompilerBlock *	vivi_decompiler_block_new		(ViviDecompilerState *		state);
+void			vivi_decompiler_block_reset		(ViviDecompilerBlock *		block);
+
+ViviCodeToken *		vivi_decompiler_block_get_label		(ViviDecompilerBlock *  	block);
+void			vivi_decompiler_block_force_label	(ViviDecompilerBlock *		block);
+const ViviDecompilerState *
+			vivi_decompiler_block_get_start_state	(ViviDecompilerBlock *	        block);
+const guint8 *		vivi_decompiler_block_get_start		(ViviDecompilerBlock *		block);
+gboolean		vivi_decompiler_block_contains		(ViviDecompilerBlock *  	block,
+								 const guint8 *			pc);
+void			vivi_decompiler_block_finish		(ViviDecompilerBlock *		block,
+								 const ViviDecompilerState *	state);
+gboolean		vivi_decompiler_block_is_finished	(ViviDecompilerBlock *		block);
+
+guint			vivi_decompiler_block_get_n_incoming	(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_set_next		(ViviDecompilerBlock *		block,
+								 ViviDecompilerBlock *		next);
+ViviDecompilerBlock *	vivi_decompiler_block_get_next		(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_set_branch	(ViviDecompilerBlock *		block,
+								 ViviDecompilerBlock *		branch,
+								 ViviCodeValue *		branch_condition);
+ViviDecompilerBlock *	vivi_decompiler_block_get_branch	(ViviDecompilerBlock *		block);
+ViviCodeValue *		vivi_decompiler_block_get_branch_condition
+								(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_add_error		(ViviDecompilerBlock *		block,
+								 const char *			format,
+								 ...) G_GNUC_PRINTF (2, 3);
+
+void			vivi_decompiler_block_add_to_block	(ViviDecompilerBlock *		block,
+								 ViviCodeBlock *		target);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivi_decompiler_state.c b/vivified/code/vivi_decompiler_state.c
new file mode 100644
index 0000000..35e29a5
--- /dev/null
+++ b/vivified/code/vivi_decompiler_state.c
@@ -0,0 +1,148 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_decompiler_state.h"
+#include "vivi_code_constant.h"
+
+struct _ViviDecompilerState {
+  SwfdecScript *	script;
+  const guint8 *	pc;
+  ViviCodeValue **	registers;
+  guint			n_registers;
+  GSList *		stack;
+  SwfdecConstantPool *	pool;
+};
+
+void
+vivi_decompiler_state_free (ViviDecompilerState *state)
+{
+  guint i;
+
+  for (i = 0; i < state->n_registers; i++) {
+    if (state->registers[i])
+      g_object_unref (state->registers[i]);
+  }
+  g_slice_free1 (sizeof (ViviCodeValue *) * state->n_registers, state->registers);
+  g_slist_foreach (state->stack, (GFunc) g_object_unref, NULL);
+  g_slist_free (state->stack);
+  if (state->pool)
+    swfdec_constant_pool_free (state->pool);
+  swfdec_script_unref (state->script);
+  g_slice_free (ViviDecompilerState, state);
+}
+
+ViviDecompilerState *
+vivi_decompiler_state_new (SwfdecScript *script, const guint8 *pc, guint n_registers)
+{
+  ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
+
+  state->script = swfdec_script_ref (script);
+  state->pc = pc;
+  state->registers = g_slice_alloc0 (sizeof (ViviCodeValue *) * n_registers);
+  state->n_registers = n_registers;
+
+  return state;
+}
+
+void
+vivi_decompiler_state_push (ViviDecompilerState *state, ViviCodeValue *val)
+{
+  state->stack = g_slist_prepend (state->stack, val);
+}
+
+ViviCodeValue *
+vivi_decompiler_state_pop (ViviDecompilerState *state)
+{
+  if (state->stack == NULL) {
+    return VIVI_CODE_VALUE (vivi_code_constant_new_undefined ());
+  } else {
+    ViviCodeValue *pop;
+    pop = state->stack->data;
+    state->stack = g_slist_remove (state->stack, pop);
+    return pop;
+  }
+}
+
+ViviDecompilerState *
+vivi_decompiler_state_copy (const ViviDecompilerState *src)
+{
+  ViviDecompilerState *dest;
+  guint i;
+
+  dest = vivi_decompiler_state_new (src->script, src->pc, src->n_registers);
+  for (i = 0; i < src->n_registers; i++) {
+    if (src->registers[i])
+      dest->registers[i] = g_object_ref (src->registers[i]);
+  }
+  dest->stack = g_slist_copy (src->stack);
+  g_slist_foreach (dest->stack, (GFunc) g_object_ref, NULL);
+  if (src->pool)
+    dest->pool = swfdec_constant_pool_copy (src->pool);
+
+  return dest;
+}
+
+ViviCodeValue *
+vivi_decompiler_state_get_register (const ViviDecompilerState *state, guint reg)
+{
+  if (reg >= state->n_registers || state->registers[state->n_registers] == NULL)
+    return VIVI_CODE_VALUE (vivi_code_constant_new_undefined ());
+  else
+    return g_object_ref (state->registers[state->n_registers]);
+}
+
+const guint8 *
+vivi_decompiler_state_get_pc (const ViviDecompilerState *state)
+{
+  return state->pc;
+}
+
+void
+vivi_decompiler_state_add_pc (ViviDecompilerState *state, int diff)
+{
+  state->pc += diff;
+}
+
+const SwfdecConstantPool *
+vivi_decompiler_state_get_constant_pool (const ViviDecompilerState *state)
+{
+  return state->pool;
+}
+
+void
+vivi_decompiler_state_set_constant_pool (ViviDecompilerState *state, 
+    SwfdecConstantPool *pool)
+{
+  if (state->pool)
+    swfdec_constant_pool_free (state->pool);
+  state->pool = pool;
+}
+
+guint
+vivi_decompiler_state_get_version (const ViviDecompilerState *state)
+{
+  return swfdec_script_get_version (state->script);
+}
+
diff --git a/vivified/code/vivi_decompiler_state.h b/vivified/code/vivi_decompiler_state.h
new file mode 100644
index 0000000..6e40b48
--- /dev/null
+++ b/vivified/code/vivi_decompiler_state.h
@@ -0,0 +1,57 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_STATE_H_
+#define _VIVI_DECOMPILER_STATE_H_
+
+#include <swfdec/swfdec.h>
+#include <vivified/code/vivi_code_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompilerState ViviDecompilerState;
+
+
+void				vivi_decompiler_state_free	(ViviDecompilerState *		state);
+ViviDecompilerState *		vivi_decompiler_state_new	(SwfdecScript *			script,
+								 const guint8 *			pc,
+								 guint				n_registers);
+ViviDecompilerState *		vivi_decompiler_state_copy	(const ViviDecompilerState *	src);
+
+void				vivi_decompiler_state_push	(ViviDecompilerState *		state,
+								 ViviCodeValue *		val);
+ViviCodeValue *			vivi_decompiler_state_pop	(ViviDecompilerState *		state);
+ViviCodeValue *			vivi_decompiler_state_get_register (const ViviDecompilerState *	state,
+								 guint				reg);
+
+const guint8 *			vivi_decompiler_state_get_pc	(const ViviDecompilerState *	state);
+void				vivi_decompiler_state_add_pc	(ViviDecompilerState *		state,
+								 int				diff);
+const SwfdecConstantPool *    	vivi_decompiler_state_get_constant_pool 
+								(const ViviDecompilerState *	state);
+void				vivi_decompiler_state_set_constant_pool 
+								(ViviDecompilerState *		state, 
+								 SwfdecConstantPool *		pool);
+guint				vivi_decompiler_state_get_version
+								(const ViviDecompilerState *  	state);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/code/vivified-compiler.h b/vivified/code/vivified-compiler.h
new file mode 100644
index 0000000..81b0539
--- /dev/null
+++ b/vivified/code/vivified-compiler.h
@@ -0,0 +1,25 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __VIVIFIED_COMPILER_H__
+#define __VIVIFIED_COMPILER_H__
+
+#include <vivified/compiler/vivi_compiler.h>
+
+#endif
diff --git a/vivified/compiler/.gitignore b/vivified/compiler/.gitignore
deleted file mode 100644
index 8761c5f..0000000
--- a/vivified/compiler/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-*~
-CVS
-.cvsignore
-.deps
-.libs
-
-Makefile
-Makefile.in
-*.o
-*.la
-*.lo
-*.loT
-
-vivi-decompile
diff --git a/vivified/compiler/Makefile.am b/vivified/compiler/Makefile.am
deleted file mode 100644
index 0fe1455..0000000
--- a/vivified/compiler/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-SUBDIRS = test
-
-noinst_LTLIBRARIES = libvivified-compiler.la
-
-libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
-libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
-
-libvivified_compiler_la_SOURCES = \
-	vivi_decompiler.c \
-	vivi_decompiler_block.c \
-	vivi_decompiler_state.c \
-	vivi_decompiler_value.c
-
-noinst_HEADERS = \
-	vivi_decompiler.h \
-	vivi_decompiler_block.h \
-	vivi_decompiler_state.h \
-	vivi_decompiler_value.h \
-	vivified-compiler.h
-
-
-noinst_PROGRAMS = vivi-decompile
-
-vivi_decompile_SOURCES = \
-	decompiler.c
-
-vivi_decompile_CFLAGS =  $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
-vivi_decompile_LDFLAGS = $(SWFDEC_LIBS)
-vivi_decompile_LDADD = libvivified-compiler.la
diff --git a/vivified/compiler/decompiler.c b/vivified/compiler/decompiler.c
deleted file mode 100644
index 7a3a58b..0000000
--- a/vivified/compiler/decompiler.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <swfdec/swfdec.h>
-
-#include <swfdec/swfdec_player_internal.h>
-#include <swfdec/swfdec_resource.h>
-#include <swfdec/swfdec_script_internal.h>
-#include <swfdec/swfdec_sprite_movie.h>
-#include <swfdec/swfdec_swf_decoder.h>
-
-#include "vivi_decompiler.h"
-
-static void
-decode_script (gpointer offset, gpointer scriptp, gpointer unused)
-{
-  SwfdecScript *script = scriptp;
-  ViviDecompiler *dec = vivi_decompiler_new (scriptp);
-  guint i;
-
-  g_print ("/* %s */\n", script->name);
-  g_print ("{\n");
-  for (i = 0; i < vivi_decompiler_get_n_lines (dec); i++) {
-    g_print ("  %s\n", vivi_decompiler_get_line (dec, i));
-  }
-  g_print ("}\n");
-  g_print ("\n");
-}
-
-int 
-main (int argc, char *argv[])
-{
-  SwfdecPlayer *player;
-  SwfdecSwfDecoder *dec;
-  SwfdecURL *url;
-
-  if (argc < 2) {
-    g_print ("%s FILENAME\n", argv[0]);
-    return 1;
-  }
-
-  player = swfdec_player_new (NULL);
-  url = swfdec_url_new_from_input (argv[1]);
-  swfdec_player_set_url (player, url);
-  swfdec_url_free (url);
-  /* FIXME: HACK! */
-  swfdec_player_advance (player, 0);
-  if (player->priv->roots == NULL ||
-      !SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data) ||
-      (dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder)) == NULL) {
-    g_printerr ("Error parsing file \"%s\"\n", argv[1]);
-    g_object_unref (player);
-    player = NULL;
-    return 1;
-  }
-
-  g_print ("/* version: %d - size: %ux%u */\n", dec->version,
-      player->priv->width, player->priv->height);
-  g_print ("\n");
-  g_hash_table_foreach (dec->scripts, decode_script, NULL);
-
-  g_object_unref (player);
-  return 0;
-}
-
diff --git a/vivified/compiler/test/Makefile.am b/vivified/compiler/test/Makefile.am
deleted file mode 100644
index 735dbd9..0000000
--- a/vivified/compiler/test/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-check-local: ../vivi-decompile
-	RESULT=0; \
-	for file in $(srcdir)/*.swf; do \
-	  ../vivi-decompile $$file | diff -u - $$file.expect || RESULT=1; \
-	done; \
-	exit $$RESULT
-
-EXTRA_DIST = \
-	hello-world.as \
-	hello-world.swf \
-	hello-world.swf.trace \
-	if.as \
-	if.swf \
-	if.swf.expect \
-	if-nested.as \
-	if-nested.swf \
-	if-nested.swf.expect
-
diff --git a/vivified/compiler/test/hello-world.as b/vivified/compiler/test/hello-world.as
deleted file mode 100644
index 27c08da..0000000
--- a/vivified/compiler/test/hello-world.as
+++ /dev/null
@@ -1,5 +0,0 @@
-// makeswf -v 7 -s 200x150 -r 1 -o hello-world.swf hello-world.as
-
-trace ("Hello World!");
-
-loadMovie ("fscommand:quit", "");
diff --git a/vivified/compiler/test/hello-world.swf b/vivified/compiler/test/hello-world.swf
deleted file mode 100644
index 18039af..0000000
Binary files a/vivified/compiler/test/hello-world.swf and /dev/null differ
diff --git a/vivified/compiler/test/hello-world.swf.expect b/vivified/compiler/test/hello-world.swf.expect
deleted file mode 100644
index bdda181..0000000
--- a/vivified/compiler/test/hello-world.swf.expect
+++ /dev/null
@@ -1,8 +0,0 @@
-/* version: 7 - size: 200x150 */
-
-/* Sprite0_Frame0 */
-{
-  trace ("Hello World!");
-  loadMovie ("fscommand:quit", "");
-}
-
diff --git a/vivified/compiler/test/if-nested.as b/vivified/compiler/test/if-nested.as
deleted file mode 100644
index 13fe78c..0000000
--- a/vivified/compiler/test/if-nested.as
+++ /dev/null
@@ -1,15 +0,0 @@
-// makeswf -v 7 -s 200x150 -r 1 -o if-nested.swf if-nested.as
-
-if (1) {
-  if (2) {
-    trace ("one");
-  } else {
-    trace ("two");
-  }
-} else {
-  if (3) {
-    trace ("three");
-  } else {
-    trace ("four");
-  }
-}
diff --git a/vivified/compiler/test/if-nested.swf b/vivified/compiler/test/if-nested.swf
deleted file mode 100644
index b5bd6db..0000000
Binary files a/vivified/compiler/test/if-nested.swf and /dev/null differ
diff --git a/vivified/compiler/test/if-nested.swf.expect b/vivified/compiler/test/if-nested.swf.expect
deleted file mode 100644
index 62e7138..0000000
--- a/vivified/compiler/test/if-nested.swf.expect
+++ /dev/null
@@ -1,20 +0,0 @@
-/* version: 7 - size: 200x150 */
-
-/* Sprite0_Frame0 */
-{
-  if (1)
-  {
-    if (2)
-      trace ("one");
-    else
-      trace ("two");
-  }
-  else
-  {
-    if (3)
-      trace ("three");
-    else
-      trace ("four");
-  }
-}
-
diff --git a/vivified/compiler/test/if.as b/vivified/compiler/test/if.as
deleted file mode 100644
index 2bc876d..0000000
--- a/vivified/compiler/test/if.as
+++ /dev/null
@@ -1,17 +0,0 @@
-// makeswf -v 7 -s 200x150 -r 1 -o if.swf if.as
-
-if (1) {
-  trace ("Hello World!");
-} else {
-  trace ("Goodbye cruel world");
-}
-
-if ("foo")
-  trace ("Hello World");
-
-if (true)
-  ;
-else
-  trace ("Goodbye cruel world");
-
-loadMovie ("fscommand:quit", "");
diff --git a/vivified/compiler/test/if.swf b/vivified/compiler/test/if.swf
deleted file mode 100644
index 21d77a5..0000000
Binary files a/vivified/compiler/test/if.swf and /dev/null differ
diff --git a/vivified/compiler/test/if.swf.expect b/vivified/compiler/test/if.swf.expect
deleted file mode 100644
index 80a3fd1..0000000
--- a/vivified/compiler/test/if.swf.expect
+++ /dev/null
@@ -1,15 +0,0 @@
-/* version: 7 - size: 200x150 */
-
-/* Sprite0_Frame0 */
-{
-  if (1)
-    trace ("Hello World!");
-  else
-    trace ("Goodbye cruel world");
-  if ("foo")
-    trace ("Hello World");
-  if (!true)
-    trace ("Goodbye cruel world");
-  loadMovie ("fscommand:quit", "");
-}
-
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
deleted file mode 100644
index 040f5d2..0000000
--- a/vivified/compiler/vivi_decompiler.c
+++ /dev/null
@@ -1,773 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include <swfdec/swfdec_as_interpret.h>
-#include <swfdec/swfdec_bits.h>
-#include <swfdec/swfdec_script_internal.h>
-
-#include "vivi_decompiler.h"
-#include "vivi_decompiler_block.h"
-#include "vivi_decompiler_state.h"
-#include "vivi_decompiler_value.h"
-
-#if 0
-static G_GNUC_UNUSED void
-DUMP_BLOCKS (ViviDecompiler *dec)
-{
-  GList *walk;
-
-  g_print ("dumping blocks:\n");
-  for (walk = dec->blocks; walk; walk = walk->next) {
-    ViviDecompilerBlock *block = walk->data;
-    g_print ("  %p -> %p\n", block->start->pc, block->exitpc);
-  }
-}
-#else
-#define DUMP_BLOCKS(dec) (void) 0
-#endif
-
-static ViviDecompilerBlock *
-vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *state)
-{
-  ViviDecompilerBlock *block;
-  GList *walk;
-  const guint8 *pc, *block_start;
-
-  DUMP_BLOCKS (dec);
-  pc = vivi_decompiler_state_get_pc (state);
-  for (walk = dec->blocks; walk; walk = walk->next) {
-    block = walk->data;
-    block_start = vivi_decompiler_block_get_start (block);
-    if (block_start < pc) {
-      if (vivi_decompiler_block_contains (block, pc)) {
-	vivi_decompiler_block_reset (block);
-	break;
-      }
-      continue;
-    }
-    if (block_start == pc) {
-      g_printerr ("FIXME: check that the blocks are equal\n");
-      vivi_decompiler_state_free (state);
-      return block;
-    }
-    break;
-  }
-
-  /* FIXME: see if the block is already there! */
-  block = vivi_decompiler_block_new (state);
-  dec->blocks = g_list_insert_before (dec->blocks, walk ? walk->next : NULL, block);
-  return block;
-}
-
-/*** BYTECODE DECOMPILER ***/
-
-typedef gboolean (* DecompileFunc) (ViviDecompilerBlock *block, ViviDecompilerState *state,
-          guint code, const guint8 *data, guint len);
-
-static char *
-escape_string (const char *s)
-{
-  GString *str;
-  char *next;
-
-  str = g_string_new ("\"");
-  while ((next = strpbrk (s, "\"\n"))) {
-    g_string_append_len (str, s, next - s);
-    switch (*next) {
-      case '"':
-	g_string_append (str, "\"");
-	break;
-      case '\n':
-	g_string_append (str, "\n");
-	break;
-      default:
-	g_assert_not_reached ();
-    }
-    s = next + 1;
-  }
-  g_string_append (str, s);
-  g_string_append_c (str, '"');
-  return g_string_free (str, FALSE);
-}
-
-static gboolean
-vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  ViviDecompilerValue *val;
-  SwfdecBits bits;
-  guint type;
-  char *value;
-
-  swfdec_bits_init_data (&bits, data, len);
-  while (swfdec_bits_left (&bits)) {
-    type = swfdec_bits_get_u8 (&bits);
-    switch (type) {
-      case 0: /* string */
-	{
-	  char *s = swfdec_bits_get_string (&bits, vivi_decompiler_state_get_version (state));
-	  if (s == NULL) {
-	    vivi_decompiler_block_emit_error (block, "could not read string");
-	    return FALSE;
-	  }
-	  value = escape_string (s);
-	  g_free (s);
-	  break;
-	}
-      case 1: /* float */
-	value = g_strdup_printf ("%f", swfdec_bits_get_float (&bits));
-	break;
-      case 2: /* null */
-	value = g_strdup ("null");
-	break;
-      case 3: /* undefined */
-	break;
-      case 4: /* register */
-	{
-	  val = vivi_decompiler_value_copy (vivi_decompiler_state_get_register (
-		state, swfdec_bits_get_u8 (&bits)));
-	  vivi_decompiler_state_push (state, val);
-	  continue;
-	}
-      case 5: /* boolean */
-	value = g_strdup (swfdec_bits_get_u8 (&bits) ? "true" : "false");
-	break;
-      case 6: /* double */
-	value = g_strdup_printf ("%g", swfdec_bits_get_double (&bits));
-	break;
-      case 7: /* 32bit int */
-	value = g_strdup_printf ("%d", swfdec_bits_get_u32 (&bits));
-	break;
-      case 8: /* 8bit ConstantPool address */
-      case 9: /* 16bit ConstantPool address */
-	{
-	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
-	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
-	  if (pool == NULL) {
-	    vivi_decompiler_block_emit_error (block, "no constant pool to push from");
-	    return FALSE;
-	  }
-	  if (i >= swfdec_constant_pool_size (pool)) {
-	    vivi_decompiler_block_emit_error (block, "constant pool index %u too high - only %u elements",
-		i, swfdec_constant_pool_size (pool));
-	    return FALSE;
-	  }
-	  value = escape_string (swfdec_constant_pool_get (pool, i));
-	  break;
-	}
-      default:
-	vivi_decompiler_block_emit_error (block, "Push: type %u not implemented", type);
-	return FALSE;
-    }
-    val = vivi_decompiler_value_new (VIVI_PRECEDENCE_NONE, TRUE, value);
-    vivi_decompiler_state_push (state, val);
-  }
-
-  return TRUE;
-}
-
-static gboolean
-vivi_decompile_pop (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  ViviDecompilerValue *val;
-  
-  val = vivi_decompiler_state_pop (state);
-  vivi_decompiler_block_emit (block, state, "%s;", vivi_decompiler_value_get_text (val));
-  vivi_decompiler_value_free (val);
-  return TRUE;
-}
-
-static gboolean
-vivi_decompile_constant_pool (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  SwfdecConstantPool *pool = swfdec_constant_pool_new_from_action (data, len, 
-      vivi_decompiler_state_get_version (state));
-
-  vivi_decompiler_state_set_constant_pool (state, pool);
-  return TRUE;
-}
-
-static gboolean
-vivi_decompile_trace (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  ViviDecompilerValue *val;
-  
-  val = vivi_decompiler_state_pop (state);
-  vivi_decompiler_block_emit (block, state, "trace (%s);", vivi_decompiler_value_get_text (val));
-  vivi_decompiler_value_free (val);
-  return TRUE;
-}
-
-static gboolean
-vivi_decompile_end (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  vivi_decompiler_block_finish (block, state);
-  return FALSE;
-}
-
-static gboolean
-vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  ViviDecompilerValue *url, *target;
-  const char *fun;
-
-  target = vivi_decompiler_state_pop (state);
-  url = vivi_decompiler_state_pop (state);
-
-  if (len != 1) {
-    vivi_decompiler_block_emit_error (block, "invalid length in getURL2 command");   
-  } else {
-    guint method = data[0] & 3;
-    guint internal = data[0] & 64;
-    guint variables = data[0] & 128;
-    if (method == 3) {
-      vivi_decompiler_block_emit_error (block, "GetURL method 3 invalid");
-      method = 0;
-    }
-
-    if (variables) {
-      fun = "loadVariables";
-    } else if (internal) {
-      fun = "loadMovie";
-    } else {
-      fun = "getURL";
-    }
-    if (method == 0) {
-      vivi_decompiler_block_emit (block, state, "%s (%s, %s);", fun, 
-	  vivi_decompiler_value_get_text (url),
-	  vivi_decompiler_value_get_text (target));
-    } else {
-      vivi_decompiler_block_emit (block, state, "%s (%s, %s, %s);", fun,
-	  vivi_decompiler_value_get_text (url),
-	  vivi_decompiler_value_get_text (target),
-	  method == 1 ? "\"GET\"" : "\"POST\"");
-    }
-  }
-  vivi_decompiler_value_free (url);
-  vivi_decompiler_value_free (target);
-  return TRUE;
-}
-
-static gboolean
-vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
-{
-  ViviDecompilerValue *pop, *push;
-
-  pop = vivi_decompiler_state_pop (state);
-  pop = vivi_decompiler_value_ensure_precedence (pop, VIVI_PRECEDENCE_UNARY);
-  push = vivi_decompiler_value_new_printf (VIVI_PRECEDENCE_UNARY,
-      vivi_decompiler_value_is_constant (pop), "!%s", vivi_decompiler_value_get_text (pop));
-  vivi_decompiler_state_push (state, push);
-  vivi_decompiler_value_free (pop);
-  return TRUE;
-}
-
-static DecompileFunc decompile_funcs[256] = {
-  [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
-  [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
-  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
-  [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
-
-  [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
-  [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
-  [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
-  [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
-  [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
-};
-
-static gboolean
-vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block, 
-    ViviDecompilerState *state, guint code, const guint8 *data, guint len)
-{
-  gboolean result;
-
-  switch (code) {
-    case SWFDEC_AS_ACTION_IF:
-      {
-	ViviDecompilerBlock *next, *branch;
-	ViviDecompilerValue *val, *val2;
-	ViviDecompilerState *new;
-	gint16 offset;
-
-	if (len != 2) {
-	  vivi_decompiler_block_emit_error (block, "If action length invalid (is %u, should be 2)", len);
-	  return FALSE;
-	}
-	offset = data[0] | (data[1] << 8);
-	vivi_decompiler_state_add_pc (state, 5);
-	val = vivi_decompiler_state_pop (state);
-	vivi_decompiler_block_finish (block, state);
-	new = vivi_decompiler_state_copy (state);
-	next = vivi_decompiler_push_block_for_state (dec, new);
-	new = vivi_decompiler_state_copy (state);
-	vivi_decompiler_state_add_pc (new, offset);
-	branch = vivi_decompiler_push_block_for_state (dec, new);
-	if (vivi_decompiler_block_is_finished (block)) {
-	  char *s, *t;
-	  ViviPrecedence prec = vivi_decompiler_value_get_precedence (val);
-	  s = t = g_strdup (vivi_decompiler_value_get_text (val));
-	  len = strlen (s);
-	  while (*s == '!') {
-	    ViviDecompilerBlock *tmp;
-	    tmp = next;
-	    next = branch;
-	    branch = tmp;
-	    s++;
-	    len--;
-	    if (s[0] == '(' && s[len - 1] == ')') {
-	      s++;
-	      len -= 2;
-	      s[len] = '\0';
-	    }
-	    prec = VIVI_PRECEDENCE_COMMA;
-	  }
-	  val2 = vivi_decompiler_value_new (prec, vivi_decompiler_value_is_constant (val),
-	      g_strdup (s));
-	  vivi_decompiler_value_free (val);
-	  vivi_decompiler_block_set_next (block, next);
-	  vivi_decompiler_block_set_branch (block, branch, val2);
-	  g_free (t);
-	}
-      }
-      return FALSE;
-    case SWFDEC_AS_ACTION_JUMP:
-      {
-	ViviDecompilerBlock *next;
-	ViviDecompilerState *new;
-	gint16 offset;
-
-	if (len != 2) {
-	  vivi_decompiler_block_emit_error (block, "Jump action length invalid (is %u, should be 2)", len);
-	  return FALSE;
-	}
-	offset = data[0] | (data[1] << 8);
-	vivi_decompiler_state_add_pc (state, 5);
-	vivi_decompiler_block_finish (block, state);
-	new = vivi_decompiler_state_copy (state);
-	vivi_decompiler_state_add_pc (new, offset);
-	next = vivi_decompiler_push_block_for_state (dec, new);
-	if (vivi_decompiler_block_is_finished (block)) {
-	  vivi_decompiler_block_set_next (block, next);
-	}
-      }
-      return FALSE;
-    default:
-      if (decompile_funcs[code]) {
-	result = decompile_funcs[code] (block, state, code, data, len);
-      } else {
-	vivi_decompiler_block_emit_error (block, "unknown bytecode 0x%02X %u", code, code);
-	result = FALSE;
-      }
-      if (data)
-	vivi_decompiler_state_add_pc (state, 3 + len);
-      else
-	vivi_decompiler_state_add_pc (state, 1);
-      return result;
-  };
-
-  return TRUE;
-}
-
-static void
-vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block)
-{
-  ViviDecompilerState *state;
-  ViviDecompilerBlock *next_block;
-  GList *list;
-  const guint8 *pc, *start, *end, *exit;
-  const guint8 *data;
-  guint code, len;
-
-  start = dec->script->buffer->data;
-  end = start + dec->script->buffer->length;
-  state = vivi_decompiler_state_copy (vivi_decompiler_block_get_start_state (block));
-  exit = dec->script->exit;
-  list = g_list_find (dec->blocks, block);
-  if (list->next) {
-    next_block = list->next->data;
-    exit = vivi_decompiler_block_get_start (next_block);
-  } else {
-    next_block = NULL;
-  }
-
-  while ((pc = vivi_decompiler_state_get_pc (state)) != exit) {
-    if (pc < start || pc >= end) {
-      vivi_decompiler_block_emit_error (block, "program counter out of range");
-      goto error;
-    }
-    code = pc[0];
-    if (code & 0x80) {
-      if (pc + 2 >= end) {
-	vivi_decompiler_block_emit_error (block, "bytecode %u length value out of range", code);
-	goto error;
-      }
-      data = pc + 3;
-      len = pc[1] | pc[2] << 8;
-      if (data + len > end) {
-	vivi_decompiler_block_emit_error (block, "bytecode %u length %u out of range", code, len);
-	goto error;
-      }
-    } else {
-      data = NULL;
-      len = 0;
-    }
-    if (!vivi_decompiler_process (dec, block, state, code, data, len))
-      goto out;
-  }
-  vivi_decompiler_block_finish (block, state);
-  if (next_block) {
-    vivi_decompiler_block_set_next (block, next_block);
-  }
-
-out:
-error:
-  vivi_decompiler_state_free (state);
-}
-
-/*** PROGRAM STRUCTURE ANALYSIS ***/
-
-static void
-vivi_decompiler_block_append_block (ViviDecompilerBlock *block, 
-    ViviDecompilerBlock *append, gboolean indent)
-{
-  guint i, lines;
-
-  lines = vivi_decompiler_block_get_n_lines (append);
-  if (indent && lines > 1)
-    vivi_decompiler_block_emit (block, NULL, "{");
-  for (i = 0; i < lines; i++) {
-    vivi_decompiler_block_emit (block, NULL, "%s%s", indent ? "  " : "",
-	vivi_decompiler_block_get_line (append, i));
-  }
-  if (indent && lines > 1)
-    vivi_decompiler_block_emit (block, NULL, "}");
-}
-
-static ViviDecompilerBlock *
-vivi_decompiler_find_start_block (ViviDecompiler *dec)
-{
-  GList *walk;
-  
-  for (walk = dec->blocks; walk; walk = walk->next) {
-    ViviDecompilerBlock *block = walk->data;
-
-    if (vivi_decompiler_block_get_start (block) == dec->script->main)
-      return block;
-  }
-  g_assert_not_reached ();
-  return NULL;
-}
-
-static void
-vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
-{
-  ViviDecompilerBlock *block, *current, *next;
-  GList *all_blocks;
-  guint max_incoming = 0;
-
-  current = vivi_decompiler_find_start_block (dec);
-  block = vivi_decompiler_block_new (vivi_decompiler_state_copy (
-	vivi_decompiler_block_get_start_state (current)));
-
-  all_blocks = g_list_copy (dec->blocks);
-  while (current) {
-    g_assert (g_list_find (dec->blocks, current));
-    dec->blocks = g_list_remove (dec->blocks, current);
-    if (vivi_decompiler_block_get_n_incoming (current) > max_incoming) {
-      vivi_decompiler_block_force_label (current);
-      vivi_decompiler_block_emit (block, NULL, "%s:", 
-	  vivi_decompiler_block_get_label (current));
-    }
-    max_incoming = 0;
-    vivi_decompiler_block_append_block (block, current, FALSE);
-    next = vivi_decompiler_block_get_branch (current);
-    if (next) {
-      vivi_decompiler_block_force_label (next);
-      vivi_decompiler_block_emit (block, NULL, "if (%s)", vivi_decompiler_value_get_text (
-	  vivi_decompiler_block_get_branch_condition (next)));
-      vivi_decompiler_block_emit (block, NULL, "  goto %s;",
-	  vivi_decompiler_block_get_label (next));
-    }
-    next = vivi_decompiler_block_get_next (current);
-    if (next == NULL || !g_list_find (dec->blocks, next))
-      next = dec->blocks ? dec->blocks->data : NULL;
-    if (vivi_decompiler_block_get_next (current) == NULL) {
-      if (next)
-	vivi_decompiler_block_emit (block, NULL, "return;");
-    } else {
-      if (next == vivi_decompiler_block_get_next (current)) {
-	max_incoming = 1;
-      } else {
-	vivi_decompiler_block_force_label (next);
-	vivi_decompiler_block_emit (block, NULL, "goto %s;", 
-	    vivi_decompiler_block_get_label (next));
-      }
-    }
-    current = next;
-  }
-  g_list_foreach (all_blocks, (GFunc) vivi_decompiler_block_free, NULL);
-  g_list_free (all_blocks);
-  g_assert (dec->blocks == NULL);
-  dec->blocks = g_list_prepend (dec->blocks, block);
-}
-
-static void
-vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
-{
-  g_assert (vivi_decompiler_block_get_n_incoming (block) == 0);
-  dec->blocks = g_list_remove (dec->blocks, block);
-  vivi_decompiler_block_free (block);
-}
-
-/*  ONE
- *   |              ==>   BLOCK
- *  TWO
- */
-static gboolean
-vivi_decompiler_merge_lines (ViviDecompiler *dec)
-{
-  ViviDecompilerBlock *block, *next;
-  const ViviDecompilerValue *val;
-  gboolean result;
-  GList *walk;
-
-  result = FALSE;
-  for (walk = dec->blocks; walk; walk = walk->next) {
-    block = walk->data;
-
-    /* This is an if block or so */
-    if (vivi_decompiler_block_get_branch (block) != NULL)
-      continue;
-    /* has no next block */
-    next = vivi_decompiler_block_get_next (block);
-    if (next == NULL)
-      continue;
-    /* The next block has multiple incoming blocks */
-    if (vivi_decompiler_block_get_n_incoming (next) != 1)
-      continue;
-
-    vivi_decompiler_block_append_block (block, next, FALSE);
-    vivi_decompiler_block_set_next (block, vivi_decompiler_block_get_next (next));
-    val = vivi_decompiler_block_get_branch_condition (next);
-    if (val) {
-      vivi_decompiler_block_set_branch (block, 
-	  vivi_decompiler_block_get_branch (next),
-	  vivi_decompiler_value_copy (val));
-    }
-    vivi_decompiler_purge_block (dec, next);
-  }
-
-  return result;
-}
-
-/*     COND
- *    /    \
- *  [IF] [ELSE]     ==>   BLOCK
- *    \    /
- *     NEXT
- */
-static gboolean
-vivi_decompiler_merge_if (ViviDecompiler *dec)
-{
-  ViviDecompilerBlock *block, *if_block, *else_block;
-  gboolean result;
-  GList *walk;
-
-  result = FALSE;
-  for (walk = dec->blocks; walk; walk = walk->next) {
-    block = walk->data;
-
-    if_block = vivi_decompiler_block_get_branch (block);
-    else_block = vivi_decompiler_block_get_next (block);
-    /* not an if block */
-    if (if_block == NULL)
-      continue;
-    /* one of the blocks doesn't exist */
-    if (if_block == vivi_decompiler_block_get_next (else_block)) 
-      if_block = NULL;
-    else if (else_block == vivi_decompiler_block_get_next (if_block))
-      else_block = NULL;
-    /* if in if in if in if... */
-    if ((else_block && vivi_decompiler_block_get_branch (else_block)) || 
-	(if_block && vivi_decompiler_block_get_branch (if_block)))
-      continue;
-    /* if other blocks reference the blocks, bail, there's loops involved */
-    if ((else_block && vivi_decompiler_block_get_n_incoming (else_block) > 1) ||
-	(if_block && vivi_decompiler_block_get_n_incoming (if_block) > 1))
-      continue;
-    /* if both blocks exist, they must have the same exit block */
-    if (if_block && else_block && 
-	vivi_decompiler_block_get_next (if_block) != vivi_decompiler_block_get_next (else_block))
-      continue;
-
-    /* FINALLY we can merge the blocks */
-    if (if_block) {
-      vivi_decompiler_block_emit (block, NULL, "if (%s)", 
-	  vivi_decompiler_value_get_text (vivi_decompiler_block_get_branch_condition (block)));
-      vivi_decompiler_block_append_block (block, if_block, TRUE);
-      vivi_decompiler_block_set_next (block,
-	  vivi_decompiler_block_get_next (if_block));
-      vivi_decompiler_block_set_branch (block, NULL, NULL);
-      vivi_decompiler_purge_block (dec, if_block);
-      if (else_block)
-	vivi_decompiler_block_emit (block, NULL, "else");
-    } else {
-      ViviDecompilerValue *cond = vivi_decompiler_value_copy (
-	  vivi_decompiler_block_get_branch_condition (block));
-      cond = vivi_decompiler_value_ensure_precedence (cond, VIVI_PRECEDENCE_UNARY);
-      vivi_decompiler_block_emit (block, NULL, "if (!%s)", vivi_decompiler_value_get_text (cond));
-      vivi_decompiler_value_free (cond);
-      vivi_decompiler_block_set_branch (block, NULL, NULL);
-    }
-    if (else_block) {
-      vivi_decompiler_block_append_block (block, else_block, TRUE);
-      vivi_decompiler_block_set_next (block,
-	  vivi_decompiler_block_get_next (else_block));
-      vivi_decompiler_purge_block (dec, else_block);
-    }
-    result = TRUE;
-  }
-
-  return result;
-}
-
-static void
-vivi_decompiler_merge_blocks (ViviDecompiler *dec)
-{
-  gboolean restart;
-
-  DUMP_BLOCKS (dec);
-
-  do {
-    restart = FALSE;
-
-    restart |= vivi_decompiler_merge_lines (dec);
-    restart |= vivi_decompiler_merge_if (dec);
-  } while (restart);
-
-  DUMP_BLOCKS (dec);
-  vivi_decompiler_merge_blocks_last_resort (dec);
-}
-
-static void
-vivi_decompiler_run (ViviDecompiler *dec)
-{
-  ViviDecompilerBlock *block;
-  ViviDecompilerState *state;
-  GList *walk;
-
-  state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
-  if (dec->script->constant_pool) {
-    vivi_decompiler_state_set_constant_pool (state,
-	swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
-	    dec->script->constant_pool->length, dec->script->version));
-  }
-  block = vivi_decompiler_block_new (state);
-  g_assert (dec->blocks == NULL);
-  dec->blocks = g_list_prepend (dec->blocks, block);
-  while (TRUE) {
-    for (walk = dec->blocks; walk; walk = walk->next) {
-      block = walk->data;
-      if (!vivi_decompiler_block_is_finished (block))
-	break;
-    }
-    if (walk == NULL)
-      break;
-    vivi_decompiler_block_decompile (dec, block);
-  }
-
-  vivi_decompiler_merge_blocks (dec);
-}
-
-/*** OBJECT ***/
-
-G_DEFINE_TYPE (ViviDecompiler, vivi_decompiler, G_TYPE_OBJECT)
-
-static void
-vivi_decompiler_dispose (GObject *object)
-{
-  ViviDecompiler *dec = VIVI_DECOMPILER (object);
-
-  if (dec->script) {
-    swfdec_script_unref (dec->script);
-    dec->script = NULL;
-  }
-  g_list_foreach (dec->blocks, (GFunc) vivi_decompiler_block_free, NULL);
-  g_list_free (dec->blocks);
-  dec->blocks = NULL;
-
-  G_OBJECT_CLASS (vivi_decompiler_parent_class)->dispose (object);
-}
-
-static void
-vivi_decompiler_class_init (ViviDecompilerClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = vivi_decompiler_dispose;
-}
-
-static void
-vivi_decompiler_init (ViviDecompiler *dec)
-{
-}
-
-ViviDecompiler *
-vivi_decompiler_new (SwfdecScript *script)
-{
-  ViviDecompiler *dec = g_object_new (VIVI_TYPE_DECOMPILER, NULL);
-
-  dec->script = swfdec_script_ref (script);
-  vivi_decompiler_run (dec);
-
-  return dec;
-}
-
-guint
-vivi_decompiler_get_n_lines (ViviDecompiler *dec)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), 0);
-
-  if (dec->blocks == NULL)
-    return 0;
-
-  return vivi_decompiler_block_get_n_lines (dec->blocks->data);
-}
-
-const char *
-vivi_decompiler_get_line (ViviDecompiler *dec, guint i)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
-  g_return_val_if_fail (dec->blocks != NULL, NULL);
-
-  return vivi_decompiler_block_get_line (dec->blocks->data, i);
-}
-
diff --git a/vivified/compiler/vivi_decompiler.h b/vivified/compiler/vivi_decompiler.h
deleted file mode 100644
index f694948..0000000
--- a/vivified/compiler/vivi_decompiler.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_DECOMPILER_H_
-#define _VIVI_DECOMPILER_H_
-
-#include <swfdec/swfdec.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _ViviDecompiler ViviDecompiler;
-typedef struct _ViviDecompilerClass ViviDecompilerClass;
-
-#define VIVI_TYPE_DECOMPILER                    (vivi_decompiler_get_type())
-#define VIVI_IS_DECOMPILER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER))
-#define VIVI_IS_DECOMPILER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER))
-#define VIVI_DECOMPILER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER, ViviDecompiler))
-#define VIVI_DECOMPILER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
-#define VIVI_DECOMPILER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
-
-struct _ViviDecompiler
-{
-  SwfdecAsObject	object;
-
-  SwfdecScript *	script;		/* script that we decompile */
-  GList *		blocks;		/* list of all blocks in this script ordered by pc (should be one after decompilation is done) */
-};
-
-struct _ViviDecompilerClass
-{
-  SwfdecAsObjectClass	object_class;
-};
-
-GType			vivi_decompiler_get_type   	(void);
-
-ViviDecompiler *	vivi_decompiler_new		(SwfdecScript *		script);
-guint			vivi_decompiler_get_n_lines	(ViviDecompiler *	dec);
-const char *		vivi_decompiler_get_line	(ViviDecompiler *	dec,
-							 guint			i);
-
-G_END_DECLS
-#endif
diff --git a/vivified/compiler/vivi_decompiler_block.c b/vivified/compiler/vivi_decompiler_block.c
deleted file mode 100644
index 5dc2674..0000000
--- a/vivified/compiler/vivi_decompiler_block.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <swfdec/swfdec_script_internal.h>
-
-#include "vivi_decompiler_block.h"
-
-struct _ViviDecompilerBlock {
-  ViviDecompilerState *	start;		/* starting state */
-  GPtrArray *		lines;		/* lines parsed from this block */
-  guint			incoming;	/* number of incoming blocks */
-  char *		label;		/* label generated for this block, so we can goto it */
-  const guint8 *	startpc;	/* pointer to first command in block */
-  /* set by parsing the block */
-  const guint8 *	endpc;		/* pointer to after last parsed command or NULL if not parsed yet */
-  ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
-  ViviDecompilerBlock *	branch;		/* NULL or block branched to i if statement */
-  ViviDecompilerValue *	branch_condition;/* NULL or value for deciding if a branch should be taken */
-};
-
-void
-vivi_decompiler_block_reset (ViviDecompilerBlock *block)
-{
-  guint i;
-
-  for (i = 0; i < block->lines->len; i++) {
-    g_free (g_ptr_array_index (block->lines, i));
-  }
-  g_ptr_array_set_size (block->lines, 0);
-  vivi_decompiler_block_set_next (block, NULL);
-  vivi_decompiler_block_set_branch (block, NULL, NULL);
-  block->endpc = NULL;
-}
-
-void
-vivi_decompiler_block_free (ViviDecompilerBlock *block)
-{
-  vivi_decompiler_block_reset (block);
-  vivi_decompiler_state_free (block->start);
-  g_ptr_array_free (block->lines, TRUE);
-  g_free (block->label);
-  g_slice_free (ViviDecompilerBlock, block);
-}
-
-ViviDecompilerBlock *
-vivi_decompiler_block_new (ViviDecompilerState *state)
-{
-  ViviDecompilerBlock *block;
-
-  block = g_slice_new0 (ViviDecompilerBlock);
-  block->start = state;
-  block->startpc = vivi_decompiler_state_get_pc (state);
-  block->lines = g_ptr_array_new ();
-
-  return block;
-}
-
-const char *
-vivi_decompiler_block_get_label (const ViviDecompilerBlock *block)
-{
-  return block->label;
-}
-
-void
-vivi_decompiler_block_force_label (ViviDecompilerBlock *block)
-{
-  /* NB: label must be unique for the function we parse */
-  if (block->label == NULL)
-    block->label = g_strdup_printf ("label_%p", block);
-}
-
-
-void
-vivi_decompiler_block_set_next (ViviDecompilerBlock *block, ViviDecompilerBlock *next)
-{
-  if (block->next)
-    block->next->incoming--;
-  block->next = next;
-  if (next)
-    next->incoming++;
-}
-
-ViviDecompilerBlock *
-vivi_decompiler_block_get_next (ViviDecompilerBlock *block)
-{
-  return block->next;
-}
-
-void
-vivi_decompiler_block_set_branch (ViviDecompilerBlock *block, ViviDecompilerBlock *branch,
-    ViviDecompilerValue *branch_condition)
-{
-  g_return_if_fail ((branch != NULL) ^ (branch_condition == NULL));
-
-  if (block->branch) {
-    block->branch->incoming--;
-    vivi_decompiler_value_free (block->branch_condition);
-  }
-  block->branch = branch;
-  block->branch_condition = branch_condition;
-  if (branch)
-    branch->incoming++;
-}
-
-ViviDecompilerBlock *
-vivi_decompiler_block_get_branch (ViviDecompilerBlock *block)
-{
-  return block->branch;
-}
-
-const ViviDecompilerValue *
-vivi_decompiler_block_get_branch_condition (ViviDecompilerBlock *block)
-{
-  return block->branch_condition;
-}
-
-void
-vivi_decompiler_block_emit_error (ViviDecompilerBlock *block,
-    const char *format, ...)
-{
-  va_list varargs;
-  char *s, *t;
-
-  va_start (varargs, format);
-  s = g_strdup_vprintf (format, varargs);
-  va_end (varargs);
-  t = g_strdup_printf ("/* %s */", s);
-  g_free (s);
-
-  g_ptr_array_add (block->lines, t);
-}
-
-void
-vivi_decompiler_block_emit (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    const char *format, ...)
-{
-  va_list varargs;
-  char *s;
-
-  va_start (varargs, format);
-  s = g_strdup_vprintf (format, varargs);
-  va_end (varargs);
-
-  g_ptr_array_add (block->lines, s);
-}
-
-const guint8 *
-vivi_decompiler_block_get_start (const ViviDecompilerBlock *block)
-{
-  return block->startpc;
-}
-
-gboolean
-vivi_decompiler_block_contains (const ViviDecompilerBlock *block, const guint8 *pc)
-{
-  return pc >= block->startpc && pc < block->endpc;
-}
-
-void
-vivi_decompiler_block_finish (ViviDecompilerBlock *block, const ViviDecompilerState *state)
-{
-  g_return_if_fail (block->endpc == NULL);
-
-  block->endpc = vivi_decompiler_state_get_pc (state);
-}
-
-gboolean
-vivi_decompiler_block_is_finished (const ViviDecompilerBlock *block)
-{
-  return block->endpc != NULL;
-}
-
-const ViviDecompilerState *
-vivi_decompiler_block_get_start_state (const ViviDecompilerBlock *block)
-{
-  return block->start;
-}
-
-guint
-vivi_decompiler_block_get_n_lines (ViviDecompilerBlock *block)
-{
-  return block->lines->len;
-}
-
-const char *
-vivi_decompiler_block_get_line (ViviDecompilerBlock *block, guint i)
-{
-  return g_ptr_array_index (block->lines, i);
-}
-
-guint
-vivi_decompiler_block_get_n_incoming (const ViviDecompilerBlock *block)
-{
-  return block->incoming;
-}
diff --git a/vivified/compiler/vivi_decompiler_block.h b/vivified/compiler/vivi_decompiler_block.h
deleted file mode 100644
index 66fdbdb..0000000
--- a/vivified/compiler/vivi_decompiler_block.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_DECOMPILER_BLOCK_H_
-#define _VIVI_DECOMPILER_BLOCK_H_
-
-#include <swfdec/swfdec.h>
-#include <vivified/compiler/vivi_decompiler_state.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _ViviDecompilerBlock ViviDecompilerBlock;
-
-
-void			vivi_decompiler_block_free	(ViviDecompilerBlock *		block);
-void			vivi_decompiler_block_reset	(ViviDecompilerBlock *		block);
-ViviDecompilerBlock *	vivi_decompiler_block_new	(ViviDecompilerState *		state);
-
-const char *		vivi_decompiler_block_get_label	(const ViviDecompilerBlock *  	block);
-void			vivi_decompiler_block_force_label(ViviDecompilerBlock *		block);
-const ViviDecompilerState *
-		  vivi_decompiler_block_get_start_state	(const ViviDecompilerBlock *    block);
-const guint8 *		vivi_decompiler_block_get_start (const ViviDecompilerBlock *	block);
-gboolean		vivi_decompiler_block_contains	(const ViviDecompilerBlock *  	block,
-							 const guint8 *			pc);
-void			vivi_decompiler_block_finish	(ViviDecompilerBlock *		block,
-							 const ViviDecompilerState *	state);
-gboolean		vivi_decompiler_block_is_finished (const ViviDecompilerBlock *	block);
-
-guint			vivi_decompiler_block_get_n_incoming
-							(const ViviDecompilerBlock *	block);
-void			vivi_decompiler_block_set_next	(ViviDecompilerBlock *		block,
-							 ViviDecompilerBlock *		next);
-ViviDecompilerBlock *	vivi_decompiler_block_get_next	(ViviDecompilerBlock *		block);
-void			vivi_decompiler_block_set_branch(ViviDecompilerBlock *		block,
-							 ViviDecompilerBlock *		branch,
-							 ViviDecompilerValue *		branch_condition);
-ViviDecompilerBlock *	vivi_decompiler_block_get_branch(ViviDecompilerBlock *		block);
-const ViviDecompilerValue *
-			vivi_decompiler_block_get_branch_condition
-							(ViviDecompilerBlock *		block);
-void			vivi_decompiler_block_emit_error(ViviDecompilerBlock *		block,
-							 const char *			format,
-							 ...) G_GNUC_PRINTF (2, 3);
-void			vivi_decompiler_block_emit	(ViviDecompilerBlock *		block,
-							 ViviDecompilerState *		state,
-							 const char *			format,
-							 ...) G_GNUC_PRINTF (3, 4);
-guint			vivi_decompiler_block_get_n_lines(ViviDecompilerBlock *		block);
-const char *		vivi_decompiler_block_get_line	(ViviDecompilerBlock *		block,
-							 guint				i);
-
-
-G_END_DECLS
-#endif
diff --git a/vivified/compiler/vivi_decompiler_state.c b/vivified/compiler/vivi_decompiler_state.c
deleted file mode 100644
index 61db120..0000000
--- a/vivified/compiler/vivi_decompiler_state.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <swfdec/swfdec_script_internal.h>
-
-#include "vivi_decompiler_state.h"
-
-struct _ViviDecompilerState {
-  SwfdecScript *	script;
-  const guint8 *	pc;
-  ViviDecompilerValue **registers;
-  guint			n_registers;
-  GSList *		stack;
-  SwfdecConstantPool *	pool;
-};
-
-void
-vivi_decompiler_state_free (ViviDecompilerState *state)
-{
-  guint i;
-
-  for (i = 0; i < state->n_registers; i++) {
-    if (state->registers[i])
-      vivi_decompiler_value_free (state->registers[i]);
-  }
-  g_slice_free1 (sizeof (ViviDecompilerValue *) * state->n_registers, state->registers);
-  g_slist_foreach (state->stack, (GFunc) vivi_decompiler_value_free, NULL);
-  g_slist_free (state->stack);
-  if (state->pool)
-    swfdec_constant_pool_free (state->pool);
-  swfdec_script_unref (state->script);
-  g_slice_free (ViviDecompilerState, state);
-}
-
-ViviDecompilerState *
-vivi_decompiler_state_new (SwfdecScript *script, const guint8 *pc, guint n_registers)
-{
-  ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
-
-  state->script = swfdec_script_ref (script);
-  state->pc = pc;
-  state->registers = g_slice_alloc0 (sizeof (ViviDecompilerValue *) * n_registers);
-  state->n_registers = n_registers;
-
-  return state;
-}
-
-void
-vivi_decompiler_state_push (ViviDecompilerState *state, ViviDecompilerValue *val)
-{
-  state->stack = g_slist_prepend (state->stack, val);
-}
-
-ViviDecompilerValue *
-vivi_decompiler_state_pop (ViviDecompilerState *state)
-{
-  if (state->stack == NULL) {
-    return vivi_decompiler_value_copy (vivi_decompiler_value_get_undefined ());
-  } else {
-    ViviDecompilerValue *pop;
-    pop = state->stack->data;
-    state->stack = g_slist_remove (state->stack, pop);
-    return pop;
-  }
-}
-
-ViviDecompilerState *
-vivi_decompiler_state_copy (const ViviDecompilerState *src)
-{
-  ViviDecompilerState *dest;
-  guint i;
-  GSList *walk;
-
-  dest = vivi_decompiler_state_new (src->script, src->pc, src->n_registers);
-  for (i = 0; i < src->n_registers; i++) {
-    if (src->registers[i])
-      dest->registers[i] = vivi_decompiler_value_copy (src->registers[i]);
-  }
-  for (walk = src->stack; walk; walk = walk->next) {
-    dest->stack = g_slist_prepend (dest->stack, vivi_decompiler_value_copy (walk->data));
-  }
-  dest->stack = g_slist_reverse (dest->stack);
-  if (src->pool)
-    dest->pool = swfdec_constant_pool_copy (src->pool);
-
-  return dest;
-}
-
-const ViviDecompilerValue *
-vivi_decompiler_state_get_register (const ViviDecompilerState *state, guint reg)
-{
-  if (reg >= state->n_registers || state->registers[state->n_registers] == NULL)
-    return vivi_decompiler_value_get_undefined ();
-  else
-    return state->registers[state->n_registers];
-}
-
-const guint8 *
-vivi_decompiler_state_get_pc (const ViviDecompilerState *state)
-{
-  return state->pc;
-}
-
-void
-vivi_decompiler_state_add_pc (ViviDecompilerState *state, int diff)
-{
-  state->pc += diff;
-}
-
-const SwfdecConstantPool *
-vivi_decompiler_state_get_constant_pool (const ViviDecompilerState *state)
-{
-  return state->pool;
-}
-
-void
-vivi_decompiler_state_set_constant_pool (ViviDecompilerState *state, 
-    SwfdecConstantPool *pool)
-{
-  if (state->pool)
-    swfdec_constant_pool_free (state->pool);
-  state->pool = pool;
-}
-
-guint
-vivi_decompiler_state_get_version (const ViviDecompilerState *state)
-{
-  return swfdec_script_get_version (state->script);
-}
-
diff --git a/vivified/compiler/vivi_decompiler_state.h b/vivified/compiler/vivi_decompiler_state.h
deleted file mode 100644
index 2e2145a..0000000
--- a/vivified/compiler/vivi_decompiler_state.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_DECOMPILER_STATE_H_
-#define _VIVI_DECOMPILER_STATE_H_
-
-#include <swfdec/swfdec.h>
-#include <vivified/compiler/vivi_decompiler_value.h>
-
-G_BEGIN_DECLS
-
-
-typedef struct _ViviDecompilerState ViviDecompilerState;
-
-
-void				vivi_decompiler_state_free	(ViviDecompilerState *		state);
-ViviDecompilerState *		vivi_decompiler_state_new	(SwfdecScript *			script,
-								 const guint8 *			pc,
-								 guint				n_registers);
-ViviDecompilerState *		vivi_decompiler_state_copy	(const ViviDecompilerState *	src);
-
-void				vivi_decompiler_state_push	(ViviDecompilerState *		state,
-								 ViviDecompilerValue *		val);
-ViviDecompilerValue *		vivi_decompiler_state_pop	(ViviDecompilerState *		state);
-const ViviDecompilerValue *	vivi_decompiler_state_get_register (const ViviDecompilerState *	state,
-								 guint				reg);
-
-const guint8 *			vivi_decompiler_state_get_pc	(const ViviDecompilerState *	state);
-void				vivi_decompiler_state_add_pc	(ViviDecompilerState *		state,
-								 int				diff);
-const SwfdecConstantPool *    	vivi_decompiler_state_get_constant_pool 
-								(const ViviDecompilerState *	state);
-void				vivi_decompiler_state_set_constant_pool 
-								(ViviDecompilerState *		state, 
-								 SwfdecConstantPool *		pool);
-guint				vivi_decompiler_state_get_version
-								(const ViviDecompilerState *  	state);
-
-
-G_END_DECLS
-#endif
diff --git a/vivified/compiler/vivi_decompiler_value.c b/vivified/compiler/vivi_decompiler_value.c
deleted file mode 100644
index f5f341f..0000000
--- a/vivified/compiler/vivi_decompiler_value.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "vivi_decompiler_value.h"
-
-
-#define VIVI_IS_DECOMPILER_VALUE(val) ((val) != NULL)
-
-struct _ViviDecompilerValue {
-  char *		text;
-  ViviPrecedence	precedence;
-  gboolean		constant;
-};
-
-void
-vivi_decompiler_value_free (ViviDecompilerValue *value)
-{
-  g_free (value->text);
-  g_slice_free (ViviDecompilerValue, value);
-}
-
-ViviDecompilerValue *
-vivi_decompiler_value_new (ViviPrecedence precedence, gboolean constant, char *text)
-{
-  ViviDecompilerValue *value;
-
-  g_return_val_if_fail (text != NULL, NULL);
-
-  value = g_slice_new0 (ViviDecompilerValue);
-
-  value->text = text;
-  value->precedence = precedence;
-  value->constant = constant;
-
-  return value;
-}
-
-ViviDecompilerValue *
-vivi_decompiler_value_new_printf (ViviPrecedence precedence, gboolean constant, 
-    const char *format, ...)
-{
-  va_list varargs;
-  char *s;
-
-  g_return_val_if_fail (format != NULL, NULL);
-
-  va_start (varargs, format);
-  s = g_strdup_vprintf (format, varargs);
-  va_end (varargs);
-
-  return vivi_decompiler_value_new (precedence, constant, s);
-}
-
-ViviDecompilerValue *
-vivi_decompiler_value_copy (const ViviDecompilerValue *src)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (src), NULL);
-
-  return vivi_decompiler_value_new (src->precedence, src->constant, g_strdup (src->text));
-}
-
-const char * 
-vivi_decompiler_value_get_text (const ViviDecompilerValue *value)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), "undefined");
-
-  return value->text;
-}
-
-const ViviDecompilerValue *
-vivi_decompiler_value_get_undefined (void)
-{
-  static const ViviDecompilerValue undefined = { (char *) "undefined", VIVI_PRECEDENCE_NONE, TRUE };
-
-  return &undefined;
-}
-
-ViviPrecedence
-vivi_decompiler_value_get_precedence (const ViviDecompilerValue *value)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), VIVI_PRECEDENCE_NONE);
-
-  return value->precedence;
-}
-
-gboolean
-vivi_decompiler_value_is_constant (const ViviDecompilerValue *value)
-{
-  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), FALSE);
-
-  return value->constant;
-}
-
-ViviDecompilerValue *
-vivi_decompiler_value_ensure_precedence (ViviDecompilerValue *value, ViviPrecedence precedence)
-{
-  ViviDecompilerValue *new;
-
-  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), value);
-
-  if (value->precedence <= precedence)
-    return value;
-
-  new = vivi_decompiler_value_new_printf (VIVI_PRECEDENCE_NONE, value->constant, 
-      "(%s)", value->text);
-  vivi_decompiler_value_free (value);
-
-  return new;
-}
-
diff --git a/vivified/compiler/vivi_decompiler_value.h b/vivified/compiler/vivi_decompiler_value.h
deleted file mode 100644
index 882740a..0000000
--- a/vivified/compiler/vivi_decompiler_value.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Vivified
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef _VIVI_DECOMPILER_VALUE_H_
-#define _VIVI_DECOMPILER_VALUE_H_
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-
-typedef enum {
-  VIVI_PRECEDENCE_NONE = 0,
-  VIVI_PRECEDENCE_MEMBER,
-  VIVI_PRECEDENCE_CALL,
-  VIVI_PRECEDENCE_INCREMENT,
-  VIVI_PRECEDENCE_UNARY,
-  VIVI_PRECEDENCE_MULTIPLY,
-  VIVI_PRECEDENCE_ADD,
-  VIVI_PRECEDENCE_SHIFT,
-  VIVI_PRECEDENCE_RELATIONAL,
-  VIVI_PRECEDENCE_EQUALITY,
-  VIVI_PRECEDENCE_BINARY_AND,
-  VIVI_PRECEDENCE_BINARY_XOR,
-  VIVI_PRECEDENCE_BINARY_OR,
-  VIVI_PRECEDENCE_AND,
-  VIVI_PRECEDENCE_OR,
-  VIVI_PRECEDENCE_CONDITIONAL,
-  VIVI_PRECEDENCE_ASSIGNMENT,
-  VIVI_PRECEDENCE_COMMA
-} ViviPrecedence;
-
-typedef struct _ViviDecompilerValue ViviDecompilerValue;
-
-
-void				vivi_decompiler_value_free		(ViviDecompilerValue *		value);
-ViviDecompilerValue *		vivi_decompiler_value_new		(ViviPrecedence			precedence,
-									 gboolean			constant,
-									 char *			        text);
-ViviDecompilerValue *		vivi_decompiler_value_new_printf      	(ViviPrecedence			precedence,
-									 gboolean			constant,
-									 const char *			format,
-									 ...) G_GNUC_PRINTF (3, 4);
-ViviDecompilerValue *		vivi_decompiler_value_copy		(const ViviDecompilerValue *	src);
-const ViviDecompilerValue *	vivi_decompiler_value_get_undefined	(void);
-ViviDecompilerValue *		vivi_decompiler_value_ensure_precedence	(ViviDecompilerValue *          value,
-									 ViviPrecedence			precedence);
-
-const char *			vivi_decompiler_value_get_text		(const ViviDecompilerValue *	value);
-ViviPrecedence			vivi_decompiler_value_get_precedence  	(const ViviDecompilerValue *	value);
-gboolean			vivi_decompiler_value_is_constant     	(const ViviDecompilerValue *	value);
-
-G_END_DECLS
-#endif
diff --git a/vivified/compiler/vivified-compiler.h b/vivified/compiler/vivified-compiler.h
deleted file mode 100644
index 81b0539..0000000
--- a/vivified/compiler/vivified-compiler.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Swfdec
- * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
- * Boston, MA  02110-1301  USA
- */
-
-#ifndef __VIVIFIED_COMPILER_H__
-#define __VIVIFIED_COMPILER_H__
-
-#include <vivified/compiler/vivi_compiler.h>
-
-#endif
commit 59e1138ff453dfc20058c70a361d4cacbab3bece
Merge: da92077... 4c1ecab...
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Mar 17 23:00:25 2008 +0100

    Merge branch 'master' into decompiler

commit da9207766af99c98b5539b1475757c9e664d9604
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Mar 17 20:10:55 2008 +0100

    split up decompiler engine

diff --git a/vivified/compiler/Makefile.am b/vivified/compiler/Makefile.am
index 82c6a56..0fe1455 100644
--- a/vivified/compiler/Makefile.am
+++ b/vivified/compiler/Makefile.am
@@ -6,10 +6,16 @@ libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
 libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
 
 libvivified_compiler_la_SOURCES = \
-	vivi_decompiler.c
+	vivi_decompiler.c \
+	vivi_decompiler_block.c \
+	vivi_decompiler_state.c \
+	vivi_decompiler_value.c
 
 noinst_HEADERS = \
 	vivi_decompiler.h \
+	vivi_decompiler_block.h \
+	vivi_decompiler_state.h \
+	vivi_decompiler_value.h \
 	vivified-compiler.h
 
 
diff --git a/vivified/compiler/test/if.swf.expect b/vivified/compiler/test/if.swf.expect
index 7fb8861..80a3fd1 100644
--- a/vivified/compiler/test/if.swf.expect
+++ b/vivified/compiler/test/if.swf.expect
@@ -8,9 +8,7 @@
     trace ("Goodbye cruel world");
   if ("foo")
     trace ("Hello World");
-  if (true)
-    ;
-  else
+  if (!true)
     trace ("Goodbye cruel world");
   loadMovie ("fscommand:quit", "");
 }
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index f69a4bb..040f5d2 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -28,261 +28,9 @@
 #include <swfdec/swfdec_script_internal.h>
 
 #include "vivi_decompiler.h"
-
-/*** DECOMPILER ENGINE ***/
-
-typedef struct _ViviDecompilerValue ViviDecompilerValue;
-struct _ViviDecompilerValue {
-  char *	value;
-  gboolean	unconstant;
-};
-
-static void
-vivi_decompiler_value_reset (ViviDecompilerValue *value)
-{
-  g_free (value->value);
-  value->value = NULL;
-  value->unconstant = FALSE;
-}
-
-static void
-vivi_decompiler_value_copy (ViviDecompilerValue *dest, const ViviDecompilerValue *src)
-{
-  dest->value = g_strdup (src->value);
-  dest->unconstant = src->unconstant;
-}
-
-static const char * 
-vivi_decompiler_value_get (const ViviDecompilerValue *value)
-{
-  return value->value ? value->value : "undefined";
-}
-
-/* NB: takes ownership of string */
-static void
-vivi_decompiler_value_set (ViviDecompilerValue *value, char *new_string)
-{
-  g_free (value->value);
-  value->value = new_string;
-}
-
-typedef struct _ViviDecompilerState ViviDecompilerState;
-struct _ViviDecompilerState {
-  SwfdecScript *	script;
-  const guint8 *	pc;
-  ViviDecompilerValue *	registers;
-  guint			n_registers;
-  GArray *		stack;
-  SwfdecConstantPool *	pool;
-};
-
-static void
-vivi_decompiler_state_free (ViviDecompilerState *state)
-{
-  guint i;
-
-  for (i = 0; i < state->n_registers; i++) {
-    vivi_decompiler_value_reset (&state->registers[i]);
-  }
-  for (i = 0; i < state->stack->len; i++) {
-    vivi_decompiler_value_reset (&g_array_index (state->stack, ViviDecompilerValue, i));
-  }
-
-  if (state->pool)
-    swfdec_constant_pool_free (state->pool);
-  g_array_free (state->stack, TRUE);
-  g_slice_free1 (sizeof (ViviDecompilerValue) * state->n_registers, state->registers);
-  swfdec_script_unref (state->script);
-  g_slice_free (ViviDecompilerState, state);
-}
-
-static ViviDecompilerState *
-vivi_decompiler_state_new (SwfdecScript *script, const guint8 *pc, guint n_registers)
-{
-  ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
-
-  state->script = swfdec_script_ref (script);
-  state->pc = pc;
-  state->registers = g_slice_alloc0 (sizeof (ViviDecompilerValue) * n_registers);
-  state->n_registers = n_registers;
-  state->stack = g_array_new (FALSE, TRUE, sizeof (ViviDecompilerValue));
-
-  return state;
-}
-
-static void
-vivi_decompiler_state_push (ViviDecompilerState *state, ViviDecompilerValue *val)
-{
-  g_array_append_val (state->stack, *val);
-}
-
-static const ViviDecompilerValue undefined = { NULL, FALSE };
-
-static void
-vivi_decompiler_state_pop (ViviDecompilerState *state, ViviDecompilerValue *val)
-{
-  if (state->stack->len == 0) {
-    if (val)
-      *val = undefined;
-  } else {
-    ViviDecompilerValue *pop;
-    pop = &g_array_index (state->stack, ViviDecompilerValue, state->stack->len - 1);
-    if (val)
-      *val = *pop;
-    else
-      vivi_decompiler_value_reset (pop);
-  }
-
-  g_array_set_size (state->stack, state->stack->len - 1);
-}
-
-static ViviDecompilerState *
-vivi_decompiler_state_copy (const ViviDecompilerState *src)
-{
-  ViviDecompilerState *dest;
-  guint i;
-
-  dest = vivi_decompiler_state_new (src->script, src->pc, src->n_registers);
-  for (i = 0; i < src->n_registers; i++) {
-    if (src->registers[i].value)
-      vivi_decompiler_value_copy (&dest->registers[i], &src->registers[i]);
-  }
-  for (i = 0; i < src->stack->len; i++) {
-    ViviDecompilerValue val = { NULL, };
-    vivi_decompiler_value_copy (&val, 
-	&g_array_index (src->stack, ViviDecompilerValue, i));
-    vivi_decompiler_state_push (dest, &val);
-  }
-  if (src->pool)
-    dest->pool = swfdec_constant_pool_copy (src->pool);
-
-  return dest;
-}
-
-static const ViviDecompilerValue *
-vivi_decompiler_state_get_register (ViviDecompilerState *state, guint reg)
-{
-  if (reg >= state->n_registers)
-    return &undefined;
-  else
-    return &state->registers[state->n_registers];
-}
-
-/*** BLOCK ***/
-
-typedef struct _ViviDecompilerBlock ViviDecompilerBlock;
-struct _ViviDecompilerBlock {
-  ViviDecompilerState *	start;		/* starting state */
-  GPtrArray *		lines;		/* lines parsed from this block */
-  ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
-  ViviDecompilerBlock *	branch;		/* NULL or block branched to i if statement */
-  /* parsing state */
-  guint			incoming;	/* number of incoming blocks */
-  const guint8 *	exitpc;		/* pointer to after last parsed command or NULL if not parsed yet */
-  char *		label;		/* label generated for this block, so we can goto it */
-};
-
-static void
-vivi_decompiler_block_unparse (ViviDecompilerBlock *block)
-{
-  guint i;
-
-  for (i = 0; i < block->lines->len; i++) {
-    g_free (g_ptr_array_index (block->lines, i));
-  }
-  g_ptr_array_set_size (block->lines, 0);
-  block->next = NULL;
-  block->branch = NULL;
-  block->exitpc = NULL;
-}
-
-static void
-vivi_decompiler_block_free (ViviDecompilerBlock *block)
-{
-  vivi_decompiler_block_unparse (block);
-  vivi_decompiler_state_free (block->start);
-  g_ptr_array_free (block->lines, TRUE);
-  g_free (block->label);
-  g_slice_free (ViviDecompilerBlock, block);
-}
-
-static ViviDecompilerBlock *
-vivi_decompiler_block_new (ViviDecompilerState *state)
-{
-  ViviDecompilerBlock *block;
-
-  block = g_slice_new0 (ViviDecompilerBlock);
-  block->start = state;
-  block->lines = g_ptr_array_new ();
-
-  return block;
-}
-
-static const char *
-vivi_decompiler_block_get_label (ViviDecompilerBlock *block)
-{
-  /* NB: lael must be unique */
-  if (block->label == NULL)
-    block->label = g_strdup_printf ("label_%d", (int) (block->start->pc - block->start->script->main));
-
-  return block->label;
-}
-
-static void
-vivi_decompiler_block_set_next (ViviDecompilerBlock *block, ViviDecompilerBlock *next)
-{
-  if (block->next)
-    block->next->incoming--;
-  block->next = next;
-  if (next)
-    next->incoming++;
-}
-
-static void
-vivi_decompiler_block_set_branch (ViviDecompilerBlock *block, ViviDecompilerBlock *branch)
-{
-  if (block->branch)
-    block->branch->incoming--;
-  block->branch = branch;
-  if (branch)
-    branch->incoming++;
-}
-
-static void
-vivi_decompiler_block_emit_error (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    const char *format, ...) G_GNUC_PRINTF (3, 4);
-static void
-vivi_decompiler_block_emit_error (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    const char *format, ...)
-{
-  va_list varargs;
-  char *s, *t;
-
-  va_start (varargs, format);
-  s = g_strdup_vprintf (format, varargs);
-  va_end (varargs);
-  t = g_strdup_printf ("/* %s */", s);
-  g_free (s);
-
-  g_ptr_array_add (block->lines, t);
-}
-
-static void
-vivi_decompiler_block_emit_line (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    const char *format, ...) G_GNUC_PRINTF (3, 4);
-static void
-vivi_decompiler_block_emit_line (ViviDecompilerBlock *block, ViviDecompilerState *state,
-    const char *format, ...)
-{
-  va_list varargs;
-  char *s;
-
-  va_start (varargs, format);
-  s = g_strdup_vprintf (format, varargs);
-  va_end (varargs);
-
-  g_ptr_array_add (block->lines, s);
-}
+#include "vivi_decompiler_block.h"
+#include "vivi_decompiler_state.h"
+#include "vivi_decompiler_value.h"
 
 #if 0
 static G_GNUC_UNUSED void
@@ -305,20 +53,22 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 {
   ViviDecompilerBlock *block;
   GList *walk;
+  const guint8 *pc, *block_start;
 
   DUMP_BLOCKS (dec);
+  pc = vivi_decompiler_state_get_pc (state);
   for (walk = dec->blocks; walk; walk = walk->next) {
     block = walk->data;
-    if (block->start->pc < state->pc) {
-      if (block->exitpc && block->exitpc > state->pc) {
-	vivi_decompiler_block_unparse (block);
+    block_start = vivi_decompiler_block_get_start (block);
+    if (block_start < pc) {
+      if (vivi_decompiler_block_contains (block, pc)) {
+	vivi_decompiler_block_reset (block);
 	break;
       }
       continue;
     }
-    if (block->start->pc == state->pc) {
+    if (block_start == pc) {
       g_printerr ("FIXME: check that the blocks are equal\n");
-      block->incoming++;
       vivi_decompiler_state_free (state);
       return block;
     }
@@ -327,7 +77,6 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 
   /* FIXME: see if the block is already there! */
   block = vivi_decompiler_block_new (state);
-  block->incoming++;
   dec->blocks = g_list_insert_before (dec->blocks, walk ? walk->next : NULL, block);
   return block;
 }
@@ -367,73 +116,75 @@ static gboolean
 vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviDecompilerValue val;
+  ViviDecompilerValue *val;
   SwfdecBits bits;
   guint type;
+  char *value;
 
   swfdec_bits_init_data (&bits, data, len);
   while (swfdec_bits_left (&bits)) {
-    memset (&val, 0, sizeof (ViviDecompilerValue));
     type = swfdec_bits_get_u8 (&bits);
     switch (type) {
       case 0: /* string */
 	{
-	  char *s = swfdec_bits_get_string (&bits, state->script->version);
+	  char *s = swfdec_bits_get_string (&bits, vivi_decompiler_state_get_version (state));
 	  if (s == NULL) {
-	    vivi_decompiler_block_emit_error (block, state, "could not read string");
+	    vivi_decompiler_block_emit_error (block, "could not read string");
 	    return FALSE;
 	  }
-	  val.value = escape_string (s);
+	  value = escape_string (s);
 	  g_free (s);
 	  break;
 	}
       case 1: /* float */
-	val.value = g_strdup_printf ("%f", swfdec_bits_get_float (&bits));
+	value = g_strdup_printf ("%f", swfdec_bits_get_float (&bits));
 	break;
       case 2: /* null */
-	val.value = g_strdup ("null");
+	value = g_strdup ("null");
 	break;
       case 3: /* undefined */
 	break;
       case 4: /* register */
 	{
-	  vivi_decompiler_value_copy (&val,
-	      vivi_decompiler_state_get_register (state, swfdec_bits_get_u8 (&bits)));
-	  break;
+	  val = vivi_decompiler_value_copy (vivi_decompiler_state_get_register (
+		state, swfdec_bits_get_u8 (&bits)));
+	  vivi_decompiler_state_push (state, val);
+	  continue;
 	}
       case 5: /* boolean */
-	val.value = g_strdup (swfdec_bits_get_u8 (&bits) ? "true" : "false");
+	value = g_strdup (swfdec_bits_get_u8 (&bits) ? "true" : "false");
 	break;
       case 6: /* double */
-	val.value = g_strdup_printf ("%g", swfdec_bits_get_double (&bits));
+	value = g_strdup_printf ("%g", swfdec_bits_get_double (&bits));
 	break;
       case 7: /* 32bit int */
-	val.value = g_strdup_printf ("%d", swfdec_bits_get_u32 (&bits));
+	value = g_strdup_printf ("%d", swfdec_bits_get_u32 (&bits));
 	break;
       case 8: /* 8bit ConstantPool address */
       case 9: /* 16bit ConstantPool address */
 	{
 	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
-	  if (state->pool == NULL) {
-	    vivi_decompiler_block_emit_error (block, state, "no constant pool to push from");
+	  const SwfdecConstantPool *pool = vivi_decompiler_state_get_constant_pool (state);
+	  if (pool == NULL) {
+	    vivi_decompiler_block_emit_error (block, "no constant pool to push from");
 	    return FALSE;
 	  }
-	  if (i >= swfdec_constant_pool_size (state->pool)) {
-	    vivi_decompiler_block_emit_error (block, state, "constant pool index %u too high - only %u elements",
-		i, swfdec_constant_pool_size (state->pool));
+	  if (i >= swfdec_constant_pool_size (pool)) {
+	    vivi_decompiler_block_emit_error (block, "constant pool index %u too high - only %u elements",
+		i, swfdec_constant_pool_size (pool));
 	    return FALSE;
 	  }
-	  val.value = escape_string (swfdec_constant_pool_get (state->pool, i));
+	  value = escape_string (swfdec_constant_pool_get (pool, i));
 	  break;
 	}
       default:
-	vivi_decompiler_block_emit_error (block, state, "Push: type %u not implemented", type);
+	vivi_decompiler_block_emit_error (block, "Push: type %u not implemented", type);
 	return FALSE;
     }
-    vivi_decompiler_state_push (state, &val);
+    val = vivi_decompiler_value_new (VIVI_PRECEDENCE_NONE, TRUE, value);
+    vivi_decompiler_state_push (state, val);
   }
 
-  state->pc = data + len;
   return TRUE;
 }
 
@@ -441,12 +192,11 @@ static gboolean
 vivi_decompile_pop (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviDecompilerValue val;
+  ViviDecompilerValue *val;
   
-  vivi_decompiler_state_pop (state, &val);
-  state->pc++;
-  vivi_decompiler_block_emit_line (block, state, "%s;", vivi_decompiler_value_get (&val));
-  vivi_decompiler_value_reset (&val);
+  val = vivi_decompiler_state_pop (state);
+  vivi_decompiler_block_emit (block, state, "%s;", vivi_decompiler_value_get_text (val));
+  vivi_decompiler_value_free (val);
   return TRUE;
 }
 
@@ -454,11 +204,10 @@ static gboolean
 vivi_decompile_constant_pool (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  if (state->pool)
-    swfdec_constant_pool_free (state->pool);
+  SwfdecConstantPool *pool = swfdec_constant_pool_new_from_action (data, len, 
+      vivi_decompiler_state_get_version (state));
 
-  state->pool = swfdec_constant_pool_new_from_action (data, len, state->script->version);
-  state->pc = data + len;
+  vivi_decompiler_state_set_constant_pool (state, pool);
   return TRUE;
 }
 
@@ -466,12 +215,11 @@ static gboolean
 vivi_decompile_trace (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviDecompilerValue val;
+  ViviDecompilerValue *val;
   
-  vivi_decompiler_state_pop (state, &val);
-  state->pc++;
-  vivi_decompiler_block_emit_line (block, state, "trace (%s);", vivi_decompiler_value_get (&val));
-  vivi_decompiler_value_reset (&val);
+  val = vivi_decompiler_state_pop (state);
+  vivi_decompiler_block_emit (block, state, "trace (%s);", vivi_decompiler_value_get_text (val));
+  vivi_decompiler_value_free (val);
   return TRUE;
 }
 
@@ -479,6 +227,7 @@ static gboolean
 vivi_decompile_end (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
+  vivi_decompiler_block_finish (block, state);
   return FALSE;
 }
 
@@ -486,21 +235,20 @@ static gboolean
 vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviDecompilerValue url, target;
+  ViviDecompilerValue *url, *target;
   const char *fun;
 
-  vivi_decompiler_state_pop (state, &target);
-  vivi_decompiler_state_pop (state, &url);
+  target = vivi_decompiler_state_pop (state);
+  url = vivi_decompiler_state_pop (state);
 
-  state->pc = data + len;
   if (len != 1) {
-    vivi_decompiler_block_emit_error (block, state, "invalid length in getURL2 command");   
+    vivi_decompiler_block_emit_error (block, "invalid length in getURL2 command");   
   } else {
     guint method = data[0] & 3;
     guint internal = data[0] & 64;
     guint variables = data[0] & 128;
     if (method == 3) {
-      vivi_decompiler_block_emit_error (block, state, "GetURL method 3 invalid");
+      vivi_decompiler_block_emit_error (block, "GetURL method 3 invalid");
       method = 0;
     }
 
@@ -512,18 +260,18 @@ vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
       fun = "getURL";
     }
     if (method == 0) {
-      vivi_decompiler_block_emit_line (block, state, "%s (%s, %s);", fun, 
-	  vivi_decompiler_value_get (&url),
-	  vivi_decompiler_value_get (&target));
+      vivi_decompiler_block_emit (block, state, "%s (%s, %s);", fun, 
+	  vivi_decompiler_value_get_text (url),
+	  vivi_decompiler_value_get_text (target));
     } else {
-      vivi_decompiler_block_emit_line (block, state, "%s (%s, %s, %s);", fun,
-	  vivi_decompiler_value_get (&url),
-	  vivi_decompiler_value_get (&target),
+      vivi_decompiler_block_emit (block, state, "%s (%s, %s, %s);", fun,
+	  vivi_decompiler_value_get_text (url),
+	  vivi_decompiler_value_get_text (target),
 	  method == 1 ? "\"GET\"" : "\"POST\"");
     }
   }
-  vivi_decompiler_value_reset (&url);
-  vivi_decompiler_value_reset (&target);
+  vivi_decompiler_value_free (url);
+  vivi_decompiler_value_free (target);
   return TRUE;
 }
 
@@ -531,12 +279,14 @@ static gboolean
 vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  ViviDecompilerValue val;
+  ViviDecompilerValue *pop, *push;
 
-  vivi_decompiler_state_pop (state, &val);
-  vivi_decompiler_value_set (&val, g_strdup_printf ("!(%s)", vivi_decompiler_value_get (&val)));
-  vivi_decompiler_state_push (state, &val);
-  state->pc++;
+  pop = vivi_decompiler_state_pop (state);
+  pop = vivi_decompiler_value_ensure_precedence (pop, VIVI_PRECEDENCE_UNARY);
+  push = vivi_decompiler_value_new_printf (VIVI_PRECEDENCE_UNARY,
+      vivi_decompiler_value_is_constant (pop), "!%s", vivi_decompiler_value_get_text (pop));
+  vivi_decompiler_state_push (state, push);
+  vivi_decompiler_value_free (pop);
   return TRUE;
 }
 
@@ -557,41 +307,39 @@ static gboolean
 vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block, 
     ViviDecompilerState *state, guint code, const guint8 *data, guint len)
 {
+  gboolean result;
+
   switch (code) {
     case SWFDEC_AS_ACTION_IF:
       {
 	ViviDecompilerBlock *next, *branch;
-	ViviDecompilerValue val;
+	ViviDecompilerValue *val, *val2;
 	ViviDecompilerState *new;
 	gint16 offset;
 
 	if (len != 2) {
-	  vivi_decompiler_block_emit_error (block, state, "If action length invalid (is %u, should be 2)", len);
+	  vivi_decompiler_block_emit_error (block, "If action length invalid (is %u, should be 2)", len);
 	  return FALSE;
 	}
 	offset = data[0] | (data[1] << 8);
-	state->pc += 5;
-	vivi_decompiler_state_pop (state, &val);
-	block->exitpc = state->pc;
+	vivi_decompiler_state_add_pc (state, 5);
+	val = vivi_decompiler_state_pop (state);
+	vivi_decompiler_block_finish (block, state);
 	new = vivi_decompiler_state_copy (state);
 	next = vivi_decompiler_push_block_for_state (dec, new);
 	new = vivi_decompiler_state_copy (state);
-	new->pc += offset;
+	vivi_decompiler_state_add_pc (new, offset);
 	branch = vivi_decompiler_push_block_for_state (dec, new);
-	/* push_block_for_state() can unprocess this block */
-	if (block->exitpc) {
+	if (vivi_decompiler_block_is_finished (block)) {
 	  char *s, *t;
-	  block->next = next;
-	  block->branch = branch;
-	  s = t = val.value;
-	  val.value = NULL;
-	  vivi_decompiler_value_reset (&val);
+	  ViviPrecedence prec = vivi_decompiler_value_get_precedence (val);
+	  s = t = g_strdup (vivi_decompiler_value_get_text (val));
 	  len = strlen (s);
 	  while (*s == '!') {
 	    ViviDecompilerBlock *tmp;
-	    tmp = block->next;
-	    block->next = block->branch;
-	    block->branch = tmp;
+	    tmp = next;
+	    next = branch;
+	    branch = tmp;
 	    s++;
 	    len--;
 	    if (s[0] == '(' && s[len - 1] == ')') {
@@ -599,15 +347,17 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	      len -= 2;
 	      s[len] = '\0';
 	    }
+	    prec = VIVI_PRECEDENCE_COMMA;
 	  }
-	  vivi_decompiler_block_emit_line (block, state, "if (%s)", s);
+	  val2 = vivi_decompiler_value_new (prec, vivi_decompiler_value_is_constant (val),
+	      g_strdup (s));
+	  vivi_decompiler_value_free (val);
+	  vivi_decompiler_block_set_next (block, next);
+	  vivi_decompiler_block_set_branch (block, branch, val2);
 	  g_free (t);
-	} else {
-	  next->incoming--;
-	  branch->incoming--;
 	}
-	return FALSE;
       }
+      return FALSE;
     case SWFDEC_AS_ACTION_JUMP:
       {
 	ViviDecompilerBlock *next;
@@ -615,33 +365,32 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	gint16 offset;
 
 	if (len != 2) {
-	  vivi_decompiler_block_emit_error (block, state, "Jump action length invalid (is %u, should be 2)", len);
+	  vivi_decompiler_block_emit_error (block, "Jump action length invalid (is %u, should be 2)", len);
 	  return FALSE;
 	}
 	offset = data[0] | (data[1] << 8);
-	state->pc += 5;
-	block->exitpc = state->pc;
+	vivi_decompiler_state_add_pc (state, 5);
+	vivi_decompiler_block_finish (block, state);
 	new = vivi_decompiler_state_copy (state);
-	new->pc += offset;
+	vivi_decompiler_state_add_pc (new, offset);
 	next = vivi_decompiler_push_block_for_state (dec, new);
-	if (block->exitpc) {
-	  block->next = next;
-	} else {
-	  next->incoming--;
+	if (vivi_decompiler_block_is_finished (block)) {
+	  vivi_decompiler_block_set_next (block, next);
 	}
-	return FALSE;
       }
+      return FALSE;
     default:
       if (decompile_funcs[code]) {
-	return decompile_funcs[code] (block, state, code, data, len);
+	result = decompile_funcs[code] (block, state, code, data, len);
       } else {
-	vivi_decompiler_block_emit_error (block, state, "unknown bytecode 0x%02X %u", code, code);
-	if (data)
-	  state->pc = data + len;
-	else
-	  state->pc++;
-	break;
+	vivi_decompiler_block_emit_error (block, "unknown bytecode 0x%02X %u", code, code);
+	result = FALSE;
       }
+      if (data)
+	vivi_decompiler_state_add_pc (state, 3 + len);
+      else
+	vivi_decompiler_state_add_pc (state, 1);
+      return result;
   };
 
   return TRUE;
@@ -653,37 +402,37 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
   ViviDecompilerState *state;
   ViviDecompilerBlock *next_block;
   GList *list;
-  const guint8 *start, *end, *exit;
+  const guint8 *pc, *start, *end, *exit;
   const guint8 *data;
   guint code, len;
 
   start = dec->script->buffer->data;
   end = start + dec->script->buffer->length;
-  state = vivi_decompiler_state_copy (block->start);
+  state = vivi_decompiler_state_copy (vivi_decompiler_block_get_start_state (block));
   exit = dec->script->exit;
   list = g_list_find (dec->blocks, block);
   if (list->next) {
     next_block = list->next->data;
-    exit = next_block->start->pc;
+    exit = vivi_decompiler_block_get_start (next_block);
   } else {
     next_block = NULL;
   }
 
-  while (state->pc != exit) {
-    if (state->pc < start || state->pc >= end) {
-      vivi_decompiler_block_emit_error (block, state, "program counter out of range");
+  while ((pc = vivi_decompiler_state_get_pc (state)) != exit) {
+    if (pc < start || pc >= end) {
+      vivi_decompiler_block_emit_error (block, "program counter out of range");
       goto error;
     }
-    code = state->pc[0];
+    code = pc[0];
     if (code & 0x80) {
-      if (state->pc + 2 >= end) {
-	vivi_decompiler_block_emit_error (block, state, "bytecode %u length value out of range", code);
+      if (pc + 2 >= end) {
+	vivi_decompiler_block_emit_error (block, "bytecode %u length value out of range", code);
 	goto error;
       }
-      data = state->pc + 3;
-      len = state->pc[1] | state->pc[2] << 8;
+      data = pc + 3;
+      len = pc[1] | pc[2] << 8;
       if (data + len > end) {
-	vivi_decompiler_block_emit_error (block, state, "bytecode %u length %u out of range", code, len);
+	vivi_decompiler_block_emit_error (block, "bytecode %u length %u out of range", code, len);
 	goto error;
       }
     } else {
@@ -693,14 +442,13 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
     if (!vivi_decompiler_process (dec, block, state, code, data, len))
       goto out;
   }
+  vivi_decompiler_block_finish (block, state);
   if (next_block) {
-    block->next = next_block;
-    next_block->incoming++;
+    vivi_decompiler_block_set_next (block, next_block);
   }
 
 out:
 error:
-  block->exitpc = state->pc;
   vivi_decompiler_state_free (state);
 }
 
@@ -710,16 +458,17 @@ static void
 vivi_decompiler_block_append_block (ViviDecompilerBlock *block, 
     ViviDecompilerBlock *append, gboolean indent)
 {
-  guint i;
+  guint i, lines;
 
-  if (indent && append->lines->len > 1)
-    vivi_decompiler_block_emit_line (block, NULL, "{");
-  for (i = 0; i < append->lines->len; i++) {
-    vivi_decompiler_block_emit_line (block, NULL, "%s%s", indent ? "  " : "",
-	(char *) g_ptr_array_index (append->lines, i));
+  lines = vivi_decompiler_block_get_n_lines (append);
+  if (indent && lines > 1)
+    vivi_decompiler_block_emit (block, NULL, "{");
+  for (i = 0; i < lines; i++) {
+    vivi_decompiler_block_emit (block, NULL, "%s%s", indent ? "  " : "",
+	vivi_decompiler_block_get_line (append, i));
   }
-  if (indent && append->lines->len > 1)
-    vivi_decompiler_block_emit_line (block, NULL, "}");
+  if (indent && lines > 1)
+    vivi_decompiler_block_emit (block, NULL, "}");
 }
 
 static ViviDecompilerBlock *
@@ -730,7 +479,7 @@ vivi_decompiler_find_start_block (ViviDecompiler *dec)
   for (walk = dec->blocks; walk; walk = walk->next) {
     ViviDecompilerBlock *block = walk->data;
 
-    if (block->start->pc == dec->script->main)
+    if (vivi_decompiler_block_get_start (block) == dec->script->main)
       return block;
   }
   g_assert_not_reached ();
@@ -742,35 +491,44 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block, *current, *next;
   GList *all_blocks;
+  guint max_incoming = 0;
 
   current = vivi_decompiler_find_start_block (dec);
-  block = vivi_decompiler_block_new (vivi_decompiler_state_copy (current->start));
+  block = vivi_decompiler_block_new (vivi_decompiler_state_copy (
+	vivi_decompiler_block_get_start_state (current)));
 
   all_blocks = g_list_copy (dec->blocks);
   while (current) {
     g_assert (g_list_find (dec->blocks, current));
     dec->blocks = g_list_remove (dec->blocks, current);
-    if (current->incoming) {
-      vivi_decompiler_block_emit_line (block, NULL, "%s:", 
+    if (vivi_decompiler_block_get_n_incoming (current) > max_incoming) {
+      vivi_decompiler_block_force_label (current);
+      vivi_decompiler_block_emit (block, NULL, "%s:", 
 	  vivi_decompiler_block_get_label (current));
     }
+    max_incoming = 0;
     vivi_decompiler_block_append_block (block, current, FALSE);
-    if (current->branch) {
-      vivi_decompiler_block_emit_line (block, NULL, "  goto %s;",
-	  vivi_decompiler_block_get_label (current->branch));
+    next = vivi_decompiler_block_get_branch (current);
+    if (next) {
+      vivi_decompiler_block_force_label (next);
+      vivi_decompiler_block_emit (block, NULL, "if (%s)", vivi_decompiler_value_get_text (
+	  vivi_decompiler_block_get_branch_condition (next)));
+      vivi_decompiler_block_emit (block, NULL, "  goto %s;",
+	  vivi_decompiler_block_get_label (next));
     }
-    next = current->next;
+    next = vivi_decompiler_block_get_next (current);
     if (next == NULL || !g_list_find (dec->blocks, next))
       next = dec->blocks ? dec->blocks->data : NULL;
-    if (current->next == NULL) {
+    if (vivi_decompiler_block_get_next (current) == NULL) {
       if (next)
-	vivi_decompiler_block_emit_line (block, NULL, "return;");
+	vivi_decompiler_block_emit (block, NULL, "return;");
     } else {
-      if (next == current->next) {
-	next->incoming--;
+      if (next == vivi_decompiler_block_get_next (current)) {
+	max_incoming = 1;
       } else {
-	vivi_decompiler_block_emit_line (block, NULL, "goto %s;", 
-	    vivi_decompiler_block_get_label (current->next));
+	vivi_decompiler_block_force_label (next);
+	vivi_decompiler_block_emit (block, NULL, "goto %s;", 
+	    vivi_decompiler_block_get_label (next));
       }
     }
     current = next;
@@ -784,12 +542,8 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
 static void
 vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
 {
-  g_assert (block->incoming == 0);
+  g_assert (vivi_decompiler_block_get_n_incoming (block) == 0);
   dec->blocks = g_list_remove (dec->blocks, block);
-  if (block->next)
-    block->next->incoming--;
-  if (block->branch)
-    block->branch->incoming--;
   vivi_decompiler_block_free (block);
 }
 
@@ -801,6 +555,7 @@ static gboolean
 vivi_decompiler_merge_lines (ViviDecompiler *dec)
 {
   ViviDecompilerBlock *block, *next;
+  const ViviDecompilerValue *val;
   gboolean result;
   GList *walk;
 
@@ -809,19 +564,24 @@ vivi_decompiler_merge_lines (ViviDecompiler *dec)
     block = walk->data;
 
     /* This is an if block or so */
-    if (block->branch != NULL)
+    if (vivi_decompiler_block_get_branch (block) != NULL)
       continue;
     /* has no next block */
-    if (block->next == NULL)
+    next = vivi_decompiler_block_get_next (block);
+    if (next == NULL)
       continue;
     /* The next block has multiple incoming blocks */
-    if (block->next->incoming != 1)
+    if (vivi_decompiler_block_get_n_incoming (next) != 1)
       continue;
 
-    next = block->next;
     vivi_decompiler_block_append_block (block, next, FALSE);
-    vivi_decompiler_block_set_next (block, next->next);
-    vivi_decompiler_block_set_branch (block, next->branch);
+    vivi_decompiler_block_set_next (block, vivi_decompiler_block_get_next (next));
+    val = vivi_decompiler_block_get_branch_condition (next);
+    if (val) {
+      vivi_decompiler_block_set_branch (block, 
+	  vivi_decompiler_block_get_branch (next),
+	  vivi_decompiler_value_copy (val));
+    }
     vivi_decompiler_purge_block (dec, next);
   }
 
@@ -844,54 +604,53 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
   result = FALSE;
   for (walk = dec->blocks; walk; walk = walk->next) {
     block = walk->data;
+
+    if_block = vivi_decompiler_block_get_branch (block);
+    else_block = vivi_decompiler_block_get_next (block);
     /* not an if block */
-    if (block->branch == NULL)
+    if (if_block == NULL)
       continue;
-    else_block = block->next;
-    if_block = block->branch;
     /* one of the blocks doesn't exist */
-    if (if_block == else_block->next) {
-      if_block->incoming--;
+    if (if_block == vivi_decompiler_block_get_next (else_block)) 
       if_block = NULL;
-    }
-    else if (else_block == if_block->next) {
-      else_block->incoming--;
+    else if (else_block == vivi_decompiler_block_get_next (if_block))
       else_block = NULL;
-    }
     /* if in if in if in if... */
-    if ((else_block && else_block->branch) || 
-	(if_block && if_block->branch))
+    if ((else_block && vivi_decompiler_block_get_branch (else_block)) || 
+	(if_block && vivi_decompiler_block_get_branch (if_block)))
       continue;
     /* if other blocks reference the blocks, bail, there's loops involved */
-    if ((else_block && else_block->incoming > 1) ||
-	(if_block && if_block->incoming > 1))
+    if ((else_block && vivi_decompiler_block_get_n_incoming (else_block) > 1) ||
+	(if_block && vivi_decompiler_block_get_n_incoming (if_block) > 1))
       continue;
     /* if both blocks exist, they must have the same exit block */
-    if (if_block && else_block && if_block->next != else_block->next)
+    if (if_block && else_block && 
+	vivi_decompiler_block_get_next (if_block) != vivi_decompiler_block_get_next (else_block))
       continue;
 
     /* FINALLY we can merge the blocks */
-    block->branch = NULL;
     if (if_block) {
+      vivi_decompiler_block_emit (block, NULL, "if (%s)", 
+	  vivi_decompiler_value_get_text (vivi_decompiler_block_get_branch_condition (block)));
       vivi_decompiler_block_append_block (block, if_block, TRUE);
-      block->next = if_block->next;
-      if (block->next)
-	block->next->incoming++;
-      if_block->incoming--;
+      vivi_decompiler_block_set_next (block,
+	  vivi_decompiler_block_get_next (if_block));
+      vivi_decompiler_block_set_branch (block, NULL, NULL);
       vivi_decompiler_purge_block (dec, if_block);
+      if (else_block)
+	vivi_decompiler_block_emit (block, NULL, "else");
     } else {
-      vivi_decompiler_block_emit_line (block, NULL, "  ;");
-      block->next = NULL;
+      ViviDecompilerValue *cond = vivi_decompiler_value_copy (
+	  vivi_decompiler_block_get_branch_condition (block));
+      cond = vivi_decompiler_value_ensure_precedence (cond, VIVI_PRECEDENCE_UNARY);
+      vivi_decompiler_block_emit (block, NULL, "if (!%s)", vivi_decompiler_value_get_text (cond));
+      vivi_decompiler_value_free (cond);
+      vivi_decompiler_block_set_branch (block, NULL, NULL);
     }
     if (else_block) {
-      vivi_decompiler_block_emit_line (block, NULL, "else");
       vivi_decompiler_block_append_block (block, else_block, TRUE);
-      if (block->next == NULL) {
-	block->next = else_block->next;
-	if (block->next)
-	  block->next->incoming++;
-      }
-      else_block->incoming--;
+      vivi_decompiler_block_set_next (block,
+	  vivi_decompiler_block_get_next (else_block));
       vivi_decompiler_purge_block (dec, else_block);
     }
     result = TRUE;
@@ -927,8 +686,9 @@ vivi_decompiler_run (ViviDecompiler *dec)
 
   state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
   if (dec->script->constant_pool) {
-    state->pool = swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
-	dec->script->constant_pool->length, dec->script->version);
+    vivi_decompiler_state_set_constant_pool (state,
+	swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
+	    dec->script->constant_pool->length, dec->script->version));
   }
   block = vivi_decompiler_block_new (state);
   g_assert (dec->blocks == NULL);
@@ -936,7 +696,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
   while (TRUE) {
     for (walk = dec->blocks; walk; walk = walk->next) {
       block = walk->data;
-      if (block->exitpc == NULL)
+      if (!vivi_decompiler_block_is_finished (block))
 	break;
     }
     if (walk == NULL)
@@ -994,28 +754,20 @@ vivi_decompiler_new (SwfdecScript *script)
 guint
 vivi_decompiler_get_n_lines (ViviDecompiler *dec)
 {
-  ViviDecompilerBlock *block;
-
   g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), 0);
 
   if (dec->blocks == NULL)
     return 0;
 
-  block = dec->blocks->data;
-  return block->lines->len;
+  return vivi_decompiler_block_get_n_lines (dec->blocks->data);
 }
 
 const char *
 vivi_decompiler_get_line (ViviDecompiler *dec, guint i)
 {
-  ViviDecompilerBlock *block;
-
   g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
   g_return_val_if_fail (dec->blocks != NULL, NULL);
-  block = dec->blocks->data;
-  g_return_val_if_fail (i < block->lines->len, NULL);
 
-  return g_ptr_array_index (block->lines, i);
+  return vivi_decompiler_block_get_line (dec->blocks->data, i);
 }
 
-
diff --git a/vivified/compiler/vivi_decompiler.h b/vivified/compiler/vivi_decompiler.h
index ddc85ac..f694948 100644
--- a/vivified/compiler/vivi_decompiler.h
+++ b/vivified/compiler/vivi_decompiler.h
@@ -39,8 +39,8 @@ struct _ViviDecompiler
 {
   SwfdecAsObject	object;
 
-  SwfdecScript *	script;
-  GList *		blocks;
+  SwfdecScript *	script;		/* script that we decompile */
+  GList *		blocks;		/* list of all blocks in this script ordered by pc (should be one after decompilation is done) */
 };
 
 struct _ViviDecompilerClass
diff --git a/vivified/compiler/vivi_decompiler_block.c b/vivified/compiler/vivi_decompiler_block.c
new file mode 100644
index 0000000..5dc2674
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler_block.c
@@ -0,0 +1,215 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_decompiler_block.h"
+
+struct _ViviDecompilerBlock {
+  ViviDecompilerState *	start;		/* starting state */
+  GPtrArray *		lines;		/* lines parsed from this block */
+  guint			incoming;	/* number of incoming blocks */
+  char *		label;		/* label generated for this block, so we can goto it */
+  const guint8 *	startpc;	/* pointer to first command in block */
+  /* set by parsing the block */
+  const guint8 *	endpc;		/* pointer to after last parsed command or NULL if not parsed yet */
+  ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
+  ViviDecompilerBlock *	branch;		/* NULL or block branched to i if statement */
+  ViviDecompilerValue *	branch_condition;/* NULL or value for deciding if a branch should be taken */
+};
+
+void
+vivi_decompiler_block_reset (ViviDecompilerBlock *block)
+{
+  guint i;
+
+  for (i = 0; i < block->lines->len; i++) {
+    g_free (g_ptr_array_index (block->lines, i));
+  }
+  g_ptr_array_set_size (block->lines, 0);
+  vivi_decompiler_block_set_next (block, NULL);
+  vivi_decompiler_block_set_branch (block, NULL, NULL);
+  block->endpc = NULL;
+}
+
+void
+vivi_decompiler_block_free (ViviDecompilerBlock *block)
+{
+  vivi_decompiler_block_reset (block);
+  vivi_decompiler_state_free (block->start);
+  g_ptr_array_free (block->lines, TRUE);
+  g_free (block->label);
+  g_slice_free (ViviDecompilerBlock, block);
+}
+
+ViviDecompilerBlock *
+vivi_decompiler_block_new (ViviDecompilerState *state)
+{
+  ViviDecompilerBlock *block;
+
+  block = g_slice_new0 (ViviDecompilerBlock);
+  block->start = state;
+  block->startpc = vivi_decompiler_state_get_pc (state);
+  block->lines = g_ptr_array_new ();
+
+  return block;
+}
+
+const char *
+vivi_decompiler_block_get_label (const ViviDecompilerBlock *block)
+{
+  return block->label;
+}
+
+void
+vivi_decompiler_block_force_label (ViviDecompilerBlock *block)
+{
+  /* NB: label must be unique for the function we parse */
+  if (block->label == NULL)
+    block->label = g_strdup_printf ("label_%p", block);
+}
+
+
+void
+vivi_decompiler_block_set_next (ViviDecompilerBlock *block, ViviDecompilerBlock *next)
+{
+  if (block->next)
+    block->next->incoming--;
+  block->next = next;
+  if (next)
+    next->incoming++;
+}
+
+ViviDecompilerBlock *
+vivi_decompiler_block_get_next (ViviDecompilerBlock *block)
+{
+  return block->next;
+}
+
+void
+vivi_decompiler_block_set_branch (ViviDecompilerBlock *block, ViviDecompilerBlock *branch,
+    ViviDecompilerValue *branch_condition)
+{
+  g_return_if_fail ((branch != NULL) ^ (branch_condition == NULL));
+
+  if (block->branch) {
+    block->branch->incoming--;
+    vivi_decompiler_value_free (block->branch_condition);
+  }
+  block->branch = branch;
+  block->branch_condition = branch_condition;
+  if (branch)
+    branch->incoming++;
+}
+
+ViviDecompilerBlock *
+vivi_decompiler_block_get_branch (ViviDecompilerBlock *block)
+{
+  return block->branch;
+}
+
+const ViviDecompilerValue *
+vivi_decompiler_block_get_branch_condition (ViviDecompilerBlock *block)
+{
+  return block->branch_condition;
+}
+
+void
+vivi_decompiler_block_emit_error (ViviDecompilerBlock *block,
+    const char *format, ...)
+{
+  va_list varargs;
+  char *s, *t;
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+  t = g_strdup_printf ("/* %s */", s);
+  g_free (s);
+
+  g_ptr_array_add (block->lines, t);
+}
+
+void
+vivi_decompiler_block_emit (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    const char *format, ...)
+{
+  va_list varargs;
+  char *s;
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+
+  g_ptr_array_add (block->lines, s);
+}
+
+const guint8 *
+vivi_decompiler_block_get_start (const ViviDecompilerBlock *block)
+{
+  return block->startpc;
+}
+
+gboolean
+vivi_decompiler_block_contains (const ViviDecompilerBlock *block, const guint8 *pc)
+{
+  return pc >= block->startpc && pc < block->endpc;
+}
+
+void
+vivi_decompiler_block_finish (ViviDecompilerBlock *block, const ViviDecompilerState *state)
+{
+  g_return_if_fail (block->endpc == NULL);
+
+  block->endpc = vivi_decompiler_state_get_pc (state);
+}
+
+gboolean
+vivi_decompiler_block_is_finished (const ViviDecompilerBlock *block)
+{
+  return block->endpc != NULL;
+}
+
+const ViviDecompilerState *
+vivi_decompiler_block_get_start_state (const ViviDecompilerBlock *block)
+{
+  return block->start;
+}
+
+guint
+vivi_decompiler_block_get_n_lines (ViviDecompilerBlock *block)
+{
+  return block->lines->len;
+}
+
+const char *
+vivi_decompiler_block_get_line (ViviDecompilerBlock *block, guint i)
+{
+  return g_ptr_array_index (block->lines, i);
+}
+
+guint
+vivi_decompiler_block_get_n_incoming (const ViviDecompilerBlock *block)
+{
+  return block->incoming;
+}
diff --git a/vivified/compiler/vivi_decompiler_block.h b/vivified/compiler/vivi_decompiler_block.h
new file mode 100644
index 0000000..66fdbdb
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler_block.h
@@ -0,0 +1,72 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_BLOCK_H_
+#define _VIVI_DECOMPILER_BLOCK_H_
+
+#include <swfdec/swfdec.h>
+#include <vivified/compiler/vivi_decompiler_state.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompilerBlock ViviDecompilerBlock;
+
+
+void			vivi_decompiler_block_free	(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_reset	(ViviDecompilerBlock *		block);
+ViviDecompilerBlock *	vivi_decompiler_block_new	(ViviDecompilerState *		state);
+
+const char *		vivi_decompiler_block_get_label	(const ViviDecompilerBlock *  	block);
+void			vivi_decompiler_block_force_label(ViviDecompilerBlock *		block);
+const ViviDecompilerState *
+		  vivi_decompiler_block_get_start_state	(const ViviDecompilerBlock *    block);
+const guint8 *		vivi_decompiler_block_get_start (const ViviDecompilerBlock *	block);
+gboolean		vivi_decompiler_block_contains	(const ViviDecompilerBlock *  	block,
+							 const guint8 *			pc);
+void			vivi_decompiler_block_finish	(ViviDecompilerBlock *		block,
+							 const ViviDecompilerState *	state);
+gboolean		vivi_decompiler_block_is_finished (const ViviDecompilerBlock *	block);
+
+guint			vivi_decompiler_block_get_n_incoming
+							(const ViviDecompilerBlock *	block);
+void			vivi_decompiler_block_set_next	(ViviDecompilerBlock *		block,
+							 ViviDecompilerBlock *		next);
+ViviDecompilerBlock *	vivi_decompiler_block_get_next	(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_set_branch(ViviDecompilerBlock *		block,
+							 ViviDecompilerBlock *		branch,
+							 ViviDecompilerValue *		branch_condition);
+ViviDecompilerBlock *	vivi_decompiler_block_get_branch(ViviDecompilerBlock *		block);
+const ViviDecompilerValue *
+			vivi_decompiler_block_get_branch_condition
+							(ViviDecompilerBlock *		block);
+void			vivi_decompiler_block_emit_error(ViviDecompilerBlock *		block,
+							 const char *			format,
+							 ...) G_GNUC_PRINTF (2, 3);
+void			vivi_decompiler_block_emit	(ViviDecompilerBlock *		block,
+							 ViviDecompilerState *		state,
+							 const char *			format,
+							 ...) G_GNUC_PRINTF (3, 4);
+guint			vivi_decompiler_block_get_n_lines(ViviDecompilerBlock *		block);
+const char *		vivi_decompiler_block_get_line	(ViviDecompilerBlock *		block,
+							 guint				i);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/compiler/vivi_decompiler_state.c b/vivified/compiler/vivi_decompiler_state.c
new file mode 100644
index 0000000..61db120
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler_state.c
@@ -0,0 +1,150 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <swfdec/swfdec_script_internal.h>
+
+#include "vivi_decompiler_state.h"
+
+struct _ViviDecompilerState {
+  SwfdecScript *	script;
+  const guint8 *	pc;
+  ViviDecompilerValue **registers;
+  guint			n_registers;
+  GSList *		stack;
+  SwfdecConstantPool *	pool;
+};
+
+void
+vivi_decompiler_state_free (ViviDecompilerState *state)
+{
+  guint i;
+
+  for (i = 0; i < state->n_registers; i++) {
+    if (state->registers[i])
+      vivi_decompiler_value_free (state->registers[i]);
+  }
+  g_slice_free1 (sizeof (ViviDecompilerValue *) * state->n_registers, state->registers);
+  g_slist_foreach (state->stack, (GFunc) vivi_decompiler_value_free, NULL);
+  g_slist_free (state->stack);
+  if (state->pool)
+    swfdec_constant_pool_free (state->pool);
+  swfdec_script_unref (state->script);
+  g_slice_free (ViviDecompilerState, state);
+}
+
+ViviDecompilerState *
+vivi_decompiler_state_new (SwfdecScript *script, const guint8 *pc, guint n_registers)
+{
+  ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
+
+  state->script = swfdec_script_ref (script);
+  state->pc = pc;
+  state->registers = g_slice_alloc0 (sizeof (ViviDecompilerValue *) * n_registers);
+  state->n_registers = n_registers;
+
+  return state;
+}
+
+void
+vivi_decompiler_state_push (ViviDecompilerState *state, ViviDecompilerValue *val)
+{
+  state->stack = g_slist_prepend (state->stack, val);
+}
+
+ViviDecompilerValue *
+vivi_decompiler_state_pop (ViviDecompilerState *state)
+{
+  if (state->stack == NULL) {
+    return vivi_decompiler_value_copy (vivi_decompiler_value_get_undefined ());
+  } else {
+    ViviDecompilerValue *pop;
+    pop = state->stack->data;
+    state->stack = g_slist_remove (state->stack, pop);
+    return pop;
+  }
+}
+
+ViviDecompilerState *
+vivi_decompiler_state_copy (const ViviDecompilerState *src)
+{
+  ViviDecompilerState *dest;
+  guint i;
+  GSList *walk;
+
+  dest = vivi_decompiler_state_new (src->script, src->pc, src->n_registers);
+  for (i = 0; i < src->n_registers; i++) {
+    if (src->registers[i])
+      dest->registers[i] = vivi_decompiler_value_copy (src->registers[i]);
+  }
+  for (walk = src->stack; walk; walk = walk->next) {
+    dest->stack = g_slist_prepend (dest->stack, vivi_decompiler_value_copy (walk->data));
+  }
+  dest->stack = g_slist_reverse (dest->stack);
+  if (src->pool)
+    dest->pool = swfdec_constant_pool_copy (src->pool);
+
+  return dest;
+}
+
+const ViviDecompilerValue *
+vivi_decompiler_state_get_register (const ViviDecompilerState *state, guint reg)
+{
+  if (reg >= state->n_registers || state->registers[state->n_registers] == NULL)
+    return vivi_decompiler_value_get_undefined ();
+  else
+    return state->registers[state->n_registers];
+}
+
+const guint8 *
+vivi_decompiler_state_get_pc (const ViviDecompilerState *state)
+{
+  return state->pc;
+}
+
+void
+vivi_decompiler_state_add_pc (ViviDecompilerState *state, int diff)
+{
+  state->pc += diff;
+}
+
+const SwfdecConstantPool *
+vivi_decompiler_state_get_constant_pool (const ViviDecompilerState *state)
+{
+  return state->pool;
+}
+
+void
+vivi_decompiler_state_set_constant_pool (ViviDecompilerState *state, 
+    SwfdecConstantPool *pool)
+{
+  if (state->pool)
+    swfdec_constant_pool_free (state->pool);
+  state->pool = pool;
+}
+
+guint
+vivi_decompiler_state_get_version (const ViviDecompilerState *state)
+{
+  return swfdec_script_get_version (state->script);
+}
+
diff --git a/vivified/compiler/vivi_decompiler_state.h b/vivified/compiler/vivi_decompiler_state.h
new file mode 100644
index 0000000..2e2145a
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler_state.h
@@ -0,0 +1,57 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_STATE_H_
+#define _VIVI_DECOMPILER_STATE_H_
+
+#include <swfdec/swfdec.h>
+#include <vivified/compiler/vivi_decompiler_value.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompilerState ViviDecompilerState;
+
+
+void				vivi_decompiler_state_free	(ViviDecompilerState *		state);
+ViviDecompilerState *		vivi_decompiler_state_new	(SwfdecScript *			script,
+								 const guint8 *			pc,
+								 guint				n_registers);
+ViviDecompilerState *		vivi_decompiler_state_copy	(const ViviDecompilerState *	src);
+
+void				vivi_decompiler_state_push	(ViviDecompilerState *		state,
+								 ViviDecompilerValue *		val);
+ViviDecompilerValue *		vivi_decompiler_state_pop	(ViviDecompilerState *		state);
+const ViviDecompilerValue *	vivi_decompiler_state_get_register (const ViviDecompilerState *	state,
+								 guint				reg);
+
+const guint8 *			vivi_decompiler_state_get_pc	(const ViviDecompilerState *	state);
+void				vivi_decompiler_state_add_pc	(ViviDecompilerState *		state,
+								 int				diff);
+const SwfdecConstantPool *    	vivi_decompiler_state_get_constant_pool 
+								(const ViviDecompilerState *	state);
+void				vivi_decompiler_state_set_constant_pool 
+								(ViviDecompilerState *		state, 
+								 SwfdecConstantPool *		pool);
+guint				vivi_decompiler_state_get_version
+								(const ViviDecompilerState *  	state);
+
+
+G_END_DECLS
+#endif
diff --git a/vivified/compiler/vivi_decompiler_value.c b/vivified/compiler/vivi_decompiler_value.c
new file mode 100644
index 0000000..f5f341f
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler_value.c
@@ -0,0 +1,130 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_decompiler_value.h"
+
+
+#define VIVI_IS_DECOMPILER_VALUE(val) ((val) != NULL)
+
+struct _ViviDecompilerValue {
+  char *		text;
+  ViviPrecedence	precedence;
+  gboolean		constant;
+};
+
+void
+vivi_decompiler_value_free (ViviDecompilerValue *value)
+{
+  g_free (value->text);
+  g_slice_free (ViviDecompilerValue, value);
+}
+
+ViviDecompilerValue *
+vivi_decompiler_value_new (ViviPrecedence precedence, gboolean constant, char *text)
+{
+  ViviDecompilerValue *value;
+
+  g_return_val_if_fail (text != NULL, NULL);
+
+  value = g_slice_new0 (ViviDecompilerValue);
+
+  value->text = text;
+  value->precedence = precedence;
+  value->constant = constant;
+
+  return value;
+}
+
+ViviDecompilerValue *
+vivi_decompiler_value_new_printf (ViviPrecedence precedence, gboolean constant, 
+    const char *format, ...)
+{
+  va_list varargs;
+  char *s;
+
+  g_return_val_if_fail (format != NULL, NULL);
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+
+  return vivi_decompiler_value_new (precedence, constant, s);
+}
+
+ViviDecompilerValue *
+vivi_decompiler_value_copy (const ViviDecompilerValue *src)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (src), NULL);
+
+  return vivi_decompiler_value_new (src->precedence, src->constant, g_strdup (src->text));
+}
+
+const char * 
+vivi_decompiler_value_get_text (const ViviDecompilerValue *value)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), "undefined");
+
+  return value->text;
+}
+
+const ViviDecompilerValue *
+vivi_decompiler_value_get_undefined (void)
+{
+  static const ViviDecompilerValue undefined = { (char *) "undefined", VIVI_PRECEDENCE_NONE, TRUE };
+
+  return &undefined;
+}
+
+ViviPrecedence
+vivi_decompiler_value_get_precedence (const ViviDecompilerValue *value)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), VIVI_PRECEDENCE_NONE);
+
+  return value->precedence;
+}
+
+gboolean
+vivi_decompiler_value_is_constant (const ViviDecompilerValue *value)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), FALSE);
+
+  return value->constant;
+}
+
+ViviDecompilerValue *
+vivi_decompiler_value_ensure_precedence (ViviDecompilerValue *value, ViviPrecedence precedence)
+{
+  ViviDecompilerValue *new;
+
+  g_return_val_if_fail (VIVI_IS_DECOMPILER_VALUE (value), value);
+
+  if (value->precedence <= precedence)
+    return value;
+
+  new = vivi_decompiler_value_new_printf (VIVI_PRECEDENCE_NONE, value->constant, 
+      "(%s)", value->text);
+  vivi_decompiler_value_free (value);
+
+  return new;
+}
+
diff --git a/vivified/compiler/vivi_decompiler_value.h b/vivified/compiler/vivi_decompiler_value.h
new file mode 100644
index 0000000..882740a
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler_value.h
@@ -0,0 +1,70 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_VALUE_H_
+#define _VIVI_DECOMPILER_VALUE_H_
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+
+typedef enum {
+  VIVI_PRECEDENCE_NONE = 0,
+  VIVI_PRECEDENCE_MEMBER,
+  VIVI_PRECEDENCE_CALL,
+  VIVI_PRECEDENCE_INCREMENT,
+  VIVI_PRECEDENCE_UNARY,
+  VIVI_PRECEDENCE_MULTIPLY,
+  VIVI_PRECEDENCE_ADD,
+  VIVI_PRECEDENCE_SHIFT,
+  VIVI_PRECEDENCE_RELATIONAL,
+  VIVI_PRECEDENCE_EQUALITY,
+  VIVI_PRECEDENCE_BINARY_AND,
+  VIVI_PRECEDENCE_BINARY_XOR,
+  VIVI_PRECEDENCE_BINARY_OR,
+  VIVI_PRECEDENCE_AND,
+  VIVI_PRECEDENCE_OR,
+  VIVI_PRECEDENCE_CONDITIONAL,
+  VIVI_PRECEDENCE_ASSIGNMENT,
+  VIVI_PRECEDENCE_COMMA
+} ViviPrecedence;
+
+typedef struct _ViviDecompilerValue ViviDecompilerValue;
+
+
+void				vivi_decompiler_value_free		(ViviDecompilerValue *		value);
+ViviDecompilerValue *		vivi_decompiler_value_new		(ViviPrecedence			precedence,
+									 gboolean			constant,
+									 char *			        text);
+ViviDecompilerValue *		vivi_decompiler_value_new_printf      	(ViviPrecedence			precedence,
+									 gboolean			constant,
+									 const char *			format,
+									 ...) G_GNUC_PRINTF (3, 4);
+ViviDecompilerValue *		vivi_decompiler_value_copy		(const ViviDecompilerValue *	src);
+const ViviDecompilerValue *	vivi_decompiler_value_get_undefined	(void);
+ViviDecompilerValue *		vivi_decompiler_value_ensure_precedence	(ViviDecompilerValue *          value,
+									 ViviPrecedence			precedence);
+
+const char *			vivi_decompiler_value_get_text		(const ViviDecompilerValue *	value);
+ViviPrecedence			vivi_decompiler_value_get_precedence  	(const ViviDecompilerValue *	value);
+gboolean			vivi_decompiler_value_is_constant     	(const ViviDecompilerValue *	value);
+
+G_END_DECLS
+#endif
commit b70f17a9da8d7d7ae251d7d38753836156625840
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Mar 17 15:47:14 2008 +0100

    constify SwfdecConstantPool

diff --git a/swfdec/swfdec_script.c b/swfdec/swfdec_script.c
index 6e41a53..2be5df7 100644
--- a/swfdec/swfdec_script.c
+++ b/swfdec/swfdec_script.c
@@ -78,7 +78,7 @@ swfdec_constant_pool_new_from_action (const guint8 *data, guint len, guint versi
 }
 
 SwfdecConstantPool *
-swfdec_constant_pool_copy (SwfdecConstantPool *pool)
+swfdec_constant_pool_copy (const SwfdecConstantPool *pool)
 {
   SwfdecConstantPool *new;
   guint i;
@@ -109,13 +109,13 @@ swfdec_constant_pool_attach_to_context (SwfdecConstantPool *pool, SwfdecAsContex
 }
 
 guint
-swfdec_constant_pool_size (SwfdecConstantPool *pool)
+swfdec_constant_pool_size (const SwfdecConstantPool *pool)
 {
   return pool->n_strings;
 }
 
 const char *
-swfdec_constant_pool_get (SwfdecConstantPool *pool, guint i)
+swfdec_constant_pool_get (const SwfdecConstantPool *pool, guint i)
 {
   g_assert (i < pool->n_strings);
   return pool->strings[i];
diff --git a/swfdec/swfdec_script_internal.h b/swfdec/swfdec_script_internal.h
index 4ed473a..75f412c 100644
--- a/swfdec/swfdec_script_internal.h
+++ b/swfdec/swfdec_script_internal.h
@@ -69,28 +69,28 @@ const char *	swfdec_action_get_name		(guint			action);
 guint		swfdec_action_get_from_name	(const char *		name);
 
 SwfdecConstantPool *
-		swfdec_constant_pool_new_from_action	(const guint8 *		data,
-							 guint			len,
-							 guint			version);
-void		swfdec_constant_pool_free	  	(SwfdecConstantPool *	pool);
+		swfdec_constant_pool_new_from_action	(const guint8 *			data,
+							 guint				len,
+							 guint				version);
+void		swfdec_constant_pool_free	  	(SwfdecConstantPool *		pool);
 SwfdecConstantPool *
-		swfdec_constant_pool_copy		(SwfdecConstantPool *	pool);
-guint		swfdec_constant_pool_size		(SwfdecConstantPool *	pool);
-const char *	swfdec_constant_pool_get		(SwfdecConstantPool *	pool,
-							 guint			i);
-void		swfdec_constant_pool_attach_to_context	(SwfdecConstantPool *	pool,
-							 SwfdecAsContext *	context);
+		swfdec_constant_pool_copy		(const SwfdecConstantPool *	pool);
+guint		swfdec_constant_pool_size		(const SwfdecConstantPool *	pool);
+const char *	swfdec_constant_pool_get		(const SwfdecConstantPool *	pool,
+							 guint				i);
+void		swfdec_constant_pool_attach_to_context	(SwfdecConstantPool *		pool,
+							 SwfdecAsContext *		context);
 
-SwfdecScript *	swfdec_script_new_from_bits   		(SwfdecBits *		bits,
-							 const char *		name,
-							 guint			version);
+SwfdecScript *	swfdec_script_new_from_bits   		(SwfdecBits *			bits,
+							 const char *			name,
+							 guint				version);
 
-gboolean	swfdec_script_foreach			(SwfdecScript *		script,
-							 SwfdecScriptForeachFunc func,
-							 gpointer		user_data);
-char *		swfdec_script_print_action		(guint			action,
-							 const guint8 *		data,
-							 guint			len);
+gboolean	swfdec_script_foreach			(SwfdecScript *			script,
+							 SwfdecScriptForeachFunc	func,
+							 gpointer			user_data);
+char *		swfdec_script_print_action		(guint				action,
+							 const guint8 *			data,
+							 guint				len);
 
 G_END_DECLS
 
commit 67395467afeac90b82bdada83d2ba7549cfaed46
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Mar 17 15:44:55 2008 +0100

    add swfdec_script_get_version()

diff --git a/swfdec/swfdec_script.c b/swfdec/swfdec_script.c
index b8e0f38..6e41a53 100644
--- a/swfdec/swfdec_script.c
+++ b/swfdec/swfdec_script.c
@@ -305,6 +305,14 @@ swfdec_script_unref (SwfdecScript *script)
   g_free (script);
 }
 
+guint
+swfdec_script_get_version (SwfdecScript *script)
+{
+  g_return_val_if_fail (script != NULL, 0);
+
+  return script->version;
+}
+
 /*** UTILITY FUNCTIONS ***/
 
 const char *
diff --git a/swfdec/swfdec_script.h b/swfdec/swfdec_script.h
index 0881831..bcffd5e 100644
--- a/swfdec/swfdec_script.h
+++ b/swfdec/swfdec_script.h
@@ -32,6 +32,7 @@ SwfdecScript *	swfdec_script_new			(SwfdecBuffer *		buffer,
 SwfdecScript *	swfdec_script_ref			(SwfdecScript *		script);
 void		swfdec_script_unref			(SwfdecScript *		script);
 
+guint		swfdec_script_get_version		(SwfdecScript *		script);
 
 G_END_DECLS
 
commit 3682fb17276aecab51f0dc01921c195f603540f6
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 19:50:43 2008 +0100

    add another test for nested ifs

diff --git a/vivified/compiler/test/Makefile.am b/vivified/compiler/test/Makefile.am
index 73bf268..735dbd9 100644
--- a/vivified/compiler/test/Makefile.am
+++ b/vivified/compiler/test/Makefile.am
@@ -11,5 +11,8 @@ EXTRA_DIST = \
 	hello-world.swf.trace \
 	if.as \
 	if.swf \
-	if.swf.expect
+	if.swf.expect \
+	if-nested.as \
+	if-nested.swf \
+	if-nested.swf.expect
 
diff --git a/vivified/compiler/test/if-nested.as b/vivified/compiler/test/if-nested.as
new file mode 100644
index 0000000..13fe78c
--- /dev/null
+++ b/vivified/compiler/test/if-nested.as
@@ -0,0 +1,15 @@
+// makeswf -v 7 -s 200x150 -r 1 -o if-nested.swf if-nested.as
+
+if (1) {
+  if (2) {
+    trace ("one");
+  } else {
+    trace ("two");
+  }
+} else {
+  if (3) {
+    trace ("three");
+  } else {
+    trace ("four");
+  }
+}
diff --git a/vivified/compiler/test/if-nested.swf b/vivified/compiler/test/if-nested.swf
new file mode 100644
index 0000000..b5bd6db
Binary files /dev/null and b/vivified/compiler/test/if-nested.swf differ
diff --git a/vivified/compiler/test/if-nested.swf.expect b/vivified/compiler/test/if-nested.swf.expect
new file mode 100644
index 0000000..62e7138
--- /dev/null
+++ b/vivified/compiler/test/if-nested.swf.expect
@@ -0,0 +1,20 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  if (1)
+  {
+    if (2)
+      trace ("one");
+    else
+      trace ("two");
+  }
+  else
+  {
+    if (3)
+      trace ("three");
+    else
+      trace ("four");
+  }
+}
+
commit d6123149705dfb31409438557f7fcc6bacd9997e
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 19:37:34 2008 +0100

    add linear merging for blocks

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 7904004..f69a4bb 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -229,6 +229,26 @@ vivi_decompiler_block_get_label (ViviDecompilerBlock *block)
 }
 
 static void
+vivi_decompiler_block_set_next (ViviDecompilerBlock *block, ViviDecompilerBlock *next)
+{
+  if (block->next)
+    block->next->incoming--;
+  block->next = next;
+  if (next)
+    next->incoming++;
+}
+
+static void
+vivi_decompiler_block_set_branch (ViviDecompilerBlock *block, ViviDecompilerBlock *branch)
+{
+  if (block->branch)
+    block->branch->incoming--;
+  block->branch = branch;
+  if (branch)
+    branch->incoming++;
+}
+
+static void
 vivi_decompiler_block_emit_error (ViviDecompilerBlock *block, ViviDecompilerState *state,
     const char *format, ...) G_GNUC_PRINTF (3, 4);
 static void
@@ -773,6 +793,47 @@ vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
   vivi_decompiler_block_free (block);
 }
 
+/*  ONE
+ *   |              ==>   BLOCK
+ *  TWO
+ */
+static gboolean
+vivi_decompiler_merge_lines (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block, *next;
+  gboolean result;
+  GList *walk;
+
+  result = FALSE;
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    block = walk->data;
+
+    /* This is an if block or so */
+    if (block->branch != NULL)
+      continue;
+    /* has no next block */
+    if (block->next == NULL)
+      continue;
+    /* The next block has multiple incoming blocks */
+    if (block->next->incoming != 1)
+      continue;
+
+    next = block->next;
+    vivi_decompiler_block_append_block (block, next, FALSE);
+    vivi_decompiler_block_set_next (block, next->next);
+    vivi_decompiler_block_set_branch (block, next->branch);
+    vivi_decompiler_purge_block (dec, next);
+  }
+
+  return result;
+}
+
+/*     COND
+ *    /    \
+ *  [IF] [ELSE]     ==>   BLOCK
+ *    \    /
+ *     NEXT
+ */
 static gboolean
 vivi_decompiler_merge_if (ViviDecompiler *dec)
 {
@@ -849,6 +910,7 @@ vivi_decompiler_merge_blocks (ViviDecompiler *dec)
   do {
     restart = FALSE;
 
+    restart |= vivi_decompiler_merge_lines (dec);
     restart |= vivi_decompiler_merge_if (dec);
   } while (restart);
 
commit 5a080350344ef538a0d350e02a6b04cc74686aa9
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 19:19:02 2008 +0100

    change label names and fix a bug in if merging

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index ec1d393..7904004 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -223,7 +223,7 @@ vivi_decompiler_block_get_label (ViviDecompilerBlock *block)
 {
   /* NB: lael must be unique */
   if (block->label == NULL)
-    block->label = g_strdup_printf ("label_%p", block->start->pc);
+    block->label = g_strdup_printf ("label_%d", (int) (block->start->pc - block->start->script->main));
 
   return block->label;
 }
@@ -788,9 +788,6 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       continue;
     else_block = block->next;
     if_block = block->branch;
-    /* if in if in if in if... */
-    if (else_block->branch || if_block->branch)
-      continue;
     /* one of the blocks doesn't exist */
     if (if_block == else_block->next) {
       if_block->incoming--;
@@ -800,6 +797,10 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       else_block->incoming--;
       else_block = NULL;
     }
+    /* if in if in if in if... */
+    if ((else_block && else_block->branch) || 
+	(if_block && if_block->branch))
+      continue;
     /* if other blocks reference the blocks, bail, there's loops involved */
     if ((else_block && else_block->incoming > 1) ||
 	(if_block && if_block->incoming > 1))
commit 1568f1c1c93e2d52d53bdfbc7e89ad3bba7faf88
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 17:38:33 2008 +0100

    make pushing new blocks actually work
    
    Sometimes (for example in loops) the blocks are somewhat more complicated...

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index f5cb5ed..ec1d393 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -264,19 +264,37 @@ vivi_decompiler_block_emit_line (ViviDecompilerBlock *block, ViviDecompilerState
   g_ptr_array_add (block->lines, s);
 }
 
+#if 0
+static G_GNUC_UNUSED void
+DUMP_BLOCKS (ViviDecompiler *dec)
+{
+  GList *walk;
+
+  g_print ("dumping blocks:\n");
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    ViviDecompilerBlock *block = walk->data;
+    g_print ("  %p -> %p\n", block->start->pc, block->exitpc);
+  }
+}
+#else
+#define DUMP_BLOCKS(dec) (void) 0
+#endif
+
 static ViviDecompilerBlock *
 vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *state)
 {
   ViviDecompilerBlock *block;
   GList *walk;
 
+  DUMP_BLOCKS (dec);
   for (walk = dec->blocks; walk; walk = walk->next) {
     block = walk->data;
-    if (block->start->pc < state->pc)
+    if (block->start->pc < state->pc) {
+      if (block->exitpc && block->exitpc > state->pc) {
+	vivi_decompiler_block_unparse (block);
+	break;
+      }
       continue;
-    if (block->exitpc && block->exitpc > state->pc) {
-      vivi_decompiler_block_unparse (block);
-      break;
     }
     if (block->start->pc == state->pc) {
       g_printerr ("FIXME: check that the blocks are equal\n");
@@ -290,7 +308,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
   /* FIXME: see if the block is already there! */
   block = vivi_decompiler_block_new (state);
   block->incoming++;
-  dec->blocks = g_list_insert_before (dec->blocks, walk, block);
+  dec->blocks = g_list_insert_before (dec->blocks, walk ? walk->next : NULL, block);
   return block;
 }
 
@@ -522,10 +540,10 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
   switch (code) {
     case SWFDEC_AS_ACTION_IF:
       {
+	ViviDecompilerBlock *next, *branch;
 	ViviDecompilerValue val;
 	ViviDecompilerState *new;
 	gint16 offset;
-	char *s, *t;
 
 	if (len != 2) {
 	  vivi_decompiler_block_emit_error (block, state, "If action length invalid (is %u, should be 2)", len);
@@ -534,34 +552,45 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	offset = data[0] | (data[1] << 8);
 	state->pc += 5;
 	vivi_decompiler_state_pop (state, &val);
+	block->exitpc = state->pc;
 	new = vivi_decompiler_state_copy (state);
-	block->next = vivi_decompiler_push_block_for_state (dec, new);
+	next = vivi_decompiler_push_block_for_state (dec, new);
 	new = vivi_decompiler_state_copy (state);
 	new->pc += offset;
-	block->branch = vivi_decompiler_push_block_for_state (dec, new);
-	s = t = val.value;
-	val.value = NULL;
-	vivi_decompiler_value_reset (&val);
-	len = strlen (s);
-	while (*s == '!') {
-	  ViviDecompilerBlock *tmp;
-	  tmp = block->next;
-	  block->next = block->branch;
-	  block->branch = tmp;
-	  s++;
-	  len--;
-	  if (s[0] == '(' && s[len - 1] == ')') {
+	branch = vivi_decompiler_push_block_for_state (dec, new);
+	/* push_block_for_state() can unprocess this block */
+	if (block->exitpc) {
+	  char *s, *t;
+	  block->next = next;
+	  block->branch = branch;
+	  s = t = val.value;
+	  val.value = NULL;
+	  vivi_decompiler_value_reset (&val);
+	  len = strlen (s);
+	  while (*s == '!') {
+	    ViviDecompilerBlock *tmp;
+	    tmp = block->next;
+	    block->next = block->branch;
+	    block->branch = tmp;
 	    s++;
-	    len -= 2;
-	    s[len] = '\0';
+	    len--;
+	    if (s[0] == '(' && s[len - 1] == ')') {
+	      s++;
+	      len -= 2;
+	      s[len] = '\0';
+	    }
 	  }
+	  vivi_decompiler_block_emit_line (block, state, "if (%s)", s);
+	  g_free (t);
+	} else {
+	  next->incoming--;
+	  branch->incoming--;
 	}
-	vivi_decompiler_block_emit_line (block, state, "if (%s)", s);
-	g_free (t);
 	return FALSE;
       }
     case SWFDEC_AS_ACTION_JUMP:
       {
+	ViviDecompilerBlock *next;
 	ViviDecompilerState *new;
 	gint16 offset;
 
@@ -571,9 +600,15 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	}
 	offset = data[0] | (data[1] << 8);
 	state->pc += 5;
+	block->exitpc = state->pc;
 	new = vivi_decompiler_state_copy (state);
 	new->pc += offset;
-	block->next = vivi_decompiler_push_block_for_state (dec, new);
+	next = vivi_decompiler_push_block_for_state (dec, new);
+	if (block->exitpc) {
+	  block->next = next;
+	} else {
+	  next->incoming--;
+	}
 	return FALSE;
       }
     default:
@@ -808,11 +843,15 @@ vivi_decompiler_merge_blocks (ViviDecompiler *dec)
 {
   gboolean restart;
 
+  DUMP_BLOCKS (dec);
+
   do {
     restart = FALSE;
 
     restart |= vivi_decompiler_merge_if (dec);
   } while (restart);
+
+  DUMP_BLOCKS (dec);
   vivi_decompiler_merge_blocks_last_resort (dec);
 }
 
@@ -829,7 +868,6 @@ vivi_decompiler_run (ViviDecompiler *dec)
 	dec->script->constant_pool->length, dec->script->version);
   }
   block = vivi_decompiler_block_new (state);
-  state = vivi_decompiler_state_copy (state);
   g_assert (dec->blocks == NULL);
   dec->blocks = g_list_prepend (dec->blocks, block);
   while (TRUE) {
commit 686313dc0b132e65a7513f46ab5c104cbe0bd5e4
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 15:37:05 2008 +0100

    check program counter before using it, not after

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index abd2d3c..f5cb5ed 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -615,6 +615,10 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
   }
 
   while (state->pc != exit) {
+    if (state->pc < start || state->pc >= end) {
+      vivi_decompiler_block_emit_error (block, state, "program counter out of range");
+      goto error;
+    }
     code = state->pc[0];
     if (code & 0x80) {
       if (state->pc + 2 >= end) {
@@ -633,10 +637,6 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
     }
     if (!vivi_decompiler_process (dec, block, state, code, data, len))
       goto out;
-    if (state->pc < start || state->pc >= end) {
-      vivi_decompiler_block_emit_error (block, state, "program counter out of range");
-      goto error;
-    }
   }
   if (next_block) {
     block->next = next_block;
commit 4bd053c1e6750d939e4c7c8c17372572548c1800
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 15:29:13 2008 +0100

    add another test

diff --git a/vivified/compiler/test/Makefile.am b/vivified/compiler/test/Makefile.am
index d54f2c0..73bf268 100644
--- a/vivified/compiler/test/Makefile.am
+++ b/vivified/compiler/test/Makefile.am
@@ -8,4 +8,8 @@ check-local: ../vivi-decompile
 EXTRA_DIST = \
 	hello-world.as \
 	hello-world.swf \
-	hello-world.swf.trace
+	hello-world.swf.trace \
+	if.as \
+	if.swf \
+	if.swf.expect
+
diff --git a/vivified/compiler/test/if.as b/vivified/compiler/test/if.as
new file mode 100644
index 0000000..2bc876d
--- /dev/null
+++ b/vivified/compiler/test/if.as
@@ -0,0 +1,17 @@
+// makeswf -v 7 -s 200x150 -r 1 -o if.swf if.as
+
+if (1) {
+  trace ("Hello World!");
+} else {
+  trace ("Goodbye cruel world");
+}
+
+if ("foo")
+  trace ("Hello World");
+
+if (true)
+  ;
+else
+  trace ("Goodbye cruel world");
+
+loadMovie ("fscommand:quit", "");
diff --git a/vivified/compiler/test/if.swf b/vivified/compiler/test/if.swf
new file mode 100644
index 0000000..21d77a5
Binary files /dev/null and b/vivified/compiler/test/if.swf differ
diff --git a/vivified/compiler/test/if.swf.expect b/vivified/compiler/test/if.swf.expect
new file mode 100644
index 0000000..7fb8861
--- /dev/null
+++ b/vivified/compiler/test/if.swf.expect
@@ -0,0 +1,17 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  if (1)
+    trace ("Hello World!");
+  else
+    trace ("Goodbye cruel world");
+  if ("foo")
+    trace ("Hello World");
+  if (true)
+    ;
+  else
+    trace ("Goodbye cruel world");
+  loadMovie ("fscommand:quit", "");
+}
+
commit a5d6afc5ed2f97e328591ca9446b8ac0185a368b
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 15:26:04 2008 +0100

    fix comment

diff --git a/vivified/compiler/test/hello-world.as b/vivified/compiler/test/hello-world.as
index 30d5411..27c08da 100644
--- a/vivified/compiler/test/hello-world.as
+++ b/vivified/compiler/test/hello-world.as
@@ -1,4 +1,4 @@
-// makeswf -v 7 -s 200x150 -r 1 -o movie23.swf movie23.as
+// makeswf -v 7 -s 200x150 -r 1 -o hello-world.swf hello-world.as
 
 trace ("Hello World!");
 
commit aa2a998af6b24c9ebf932fda2a18b0549869c9fb
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 15:25:34 2008 +0100

    add test infrastructure for decompiler
    
    includes a test for Hello World!

diff --git a/configure.ac b/configure.ac
index 721cf8d..a995822 100644
--- a/configure.ac
+++ b/configure.ac
@@ -339,6 +339,7 @@ test/various/Makefile
 tools/Makefile
 vivified/Makefile
 vivified/compiler/Makefile
+vivified/compiler/test/Makefile
 vivified/core/Makefile
 vivified/dock/Makefile
 vivified/ui/Makefile
diff --git a/vivified/compiler/Makefile.am b/vivified/compiler/Makefile.am
index 97c8001..82c6a56 100644
--- a/vivified/compiler/Makefile.am
+++ b/vivified/compiler/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = test
+
 noinst_LTLIBRARIES = libvivified-compiler.la
 
 libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
diff --git a/vivified/compiler/test/Makefile.am b/vivified/compiler/test/Makefile.am
new file mode 100644
index 0000000..d54f2c0
--- /dev/null
+++ b/vivified/compiler/test/Makefile.am
@@ -0,0 +1,11 @@
+check-local: ../vivi-decompile
+	RESULT=0; \
+	for file in $(srcdir)/*.swf; do \
+	  ../vivi-decompile $$file | diff -u - $$file.expect || RESULT=1; \
+	done; \
+	exit $$RESULT
+
+EXTRA_DIST = \
+	hello-world.as \
+	hello-world.swf \
+	hello-world.swf.trace
diff --git a/vivified/compiler/test/hello-world.as b/vivified/compiler/test/hello-world.as
new file mode 100644
index 0000000..30d5411
--- /dev/null
+++ b/vivified/compiler/test/hello-world.as
@@ -0,0 +1,5 @@
+// makeswf -v 7 -s 200x150 -r 1 -o movie23.swf movie23.as
+
+trace ("Hello World!");
+
+loadMovie ("fscommand:quit", "");
diff --git a/vivified/compiler/test/hello-world.swf b/vivified/compiler/test/hello-world.swf
new file mode 100644
index 0000000..18039af
Binary files /dev/null and b/vivified/compiler/test/hello-world.swf differ
diff --git a/vivified/compiler/test/hello-world.swf.expect b/vivified/compiler/test/hello-world.swf.expect
new file mode 100644
index 0000000..bdda181
--- /dev/null
+++ b/vivified/compiler/test/hello-world.swf.expect
@@ -0,0 +1,8 @@
+/* version: 7 - size: 200x150 */
+
+/* Sprite0_Frame0 */
+{
+  trace ("Hello World!");
+  loadMovie ("fscommand:quit", "");
+}
+
commit 60fbbb41bd01dd29c841f6433d156439c7505205
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 14:14:44 2008 +0100

    remove brackets in not removing phase, too

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 1eaffa5..abd2d3c 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -525,7 +525,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	ViviDecompilerValue val;
 	ViviDecompilerState *new;
 	gint16 offset;
-	const char *s;
+	char *s, *t;
 
 	if (len != 2) {
 	  vivi_decompiler_block_emit_error (block, state, "If action length invalid (is %u, should be 2)", len);
@@ -539,16 +539,25 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	new = vivi_decompiler_state_copy (state);
 	new->pc += offset;
 	block->branch = vivi_decompiler_push_block_for_state (dec, new);
-	s = vivi_decompiler_value_get (&val);
+	s = t = val.value;
+	val.value = NULL;
+	vivi_decompiler_value_reset (&val);
+	len = strlen (s);
 	while (*s == '!') {
 	  ViviDecompilerBlock *tmp;
 	  tmp = block->next;
 	  block->next = block->branch;
 	  block->branch = tmp;
 	  s++;
+	  len--;
+	  if (s[0] == '(' && s[len - 1] == ')') {
+	    s++;
+	    len -= 2;
+	    s[len] = '\0';
+	  }
 	}
 	vivi_decompiler_block_emit_line (block, state, "if (%s)", s);
-	vivi_decompiler_value_reset (&val);
+	g_free (t);
 	return FALSE;
       }
     case SWFDEC_AS_ACTION_JUMP:
commit 9cc72b0faa10bb02527c3fb02152fd08603f9ef9
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 14:00:18 2008 +0100

    automatically convert if (!...) to if (...) and swap if and else blocks

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 6595939..1eaffa5 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -525,6 +525,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	ViviDecompilerValue val;
 	ViviDecompilerState *new;
 	gint16 offset;
+	const char *s;
 
 	if (len != 2) {
 	  vivi_decompiler_block_emit_error (block, state, "If action length invalid (is %u, should be 2)", len);
@@ -533,13 +534,21 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	offset = data[0] | (data[1] << 8);
 	state->pc += 5;
 	vivi_decompiler_state_pop (state, &val);
-	vivi_decompiler_block_emit_line (block, state, "if (%s)", vivi_decompiler_value_get (&val));
-	vivi_decompiler_value_reset (&val);
 	new = vivi_decompiler_state_copy (state);
 	block->next = vivi_decompiler_push_block_for_state (dec, new);
 	new = vivi_decompiler_state_copy (state);
 	new->pc += offset;
 	block->branch = vivi_decompiler_push_block_for_state (dec, new);
+	s = vivi_decompiler_value_get (&val);
+	while (*s == '!') {
+	  ViviDecompilerBlock *tmp;
+	  tmp = block->next;
+	  block->next = block->branch;
+	  block->branch = tmp;
+	  s++;
+	}
+	vivi_decompiler_block_emit_line (block, state, "if (%s)", s);
+	vivi_decompiler_value_reset (&val);
 	return FALSE;
       }
     case SWFDEC_AS_ACTION_JUMP:
commit 0cfb77205eaa319ded91f162c4db85df2b27390d
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun Mar 16 13:53:39 2008 +0100

    add support for NOT action

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 47b1f17..6595939 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -58,6 +58,14 @@ vivi_decompiler_value_get (const ViviDecompilerValue *value)
   return value->value ? value->value : "undefined";
 }
 
+/* NB: takes ownership of string */
+static void
+vivi_decompiler_value_set (ViviDecompilerValue *value, char *new_string)
+{
+  g_free (value->value);
+  value->value = new_string;
+}
+
 typedef struct _ViviDecompilerState ViviDecompilerState;
 struct _ViviDecompilerState {
   SwfdecScript *	script;
@@ -481,8 +489,22 @@ vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
   return TRUE;
 }
 
+static gboolean
+vivi_decompile_not (ViviDecompilerBlock *block, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviDecompilerValue val;
+
+  vivi_decompiler_state_pop (state, &val);
+  vivi_decompiler_value_set (&val, g_strdup_printf ("!(%s)", vivi_decompiler_value_get (&val)));
+  vivi_decompiler_state_push (state, &val);
+  state->pc++;
+  return TRUE;
+}
+
 static DecompileFunc decompile_funcs[256] = {
   [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
+  [SWFDEC_AS_ACTION_NOT] = vivi_decompile_not,
   [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
   [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
 
commit 9d948bcee124cbc6bb903e9ab77bebb36af6216c
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 21:59:47 2008 +0100

    fix refcounting of incoming links
    
    I seriously need to improve (un)setting of links to automatically handle
    the incoming variable

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 32ab393..47b1f17 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -717,10 +717,14 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
     if (else_block->branch || if_block->branch)
       continue;
     /* one of the blocks doesn't exist */
-    if (if_block == else_block->next)
+    if (if_block == else_block->next) {
+      if_block->incoming--;
       if_block = NULL;
-    else if (else_block == if_block->next)
+    }
+    else if (else_block == if_block->next) {
+      else_block->incoming--;
       else_block = NULL;
+    }
     /* if other blocks reference the blocks, bail, there's loops involved */
     if ((else_block && else_block->incoming > 1) ||
 	(if_block && if_block->incoming > 1))
commit 45bdf5fe9b0bfe0d043f92b81a6a58d06315e669
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 21:53:30 2008 +0100

    fix handling of empty if or else clauses

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 62b7795..32ab393 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -718,9 +718,9 @@ vivi_decompiler_merge_if (ViviDecompiler *dec)
       continue;
     /* one of the blocks doesn't exist */
     if (if_block == else_block->next)
-      else_block = NULL;
-    else if (else_block == if_block->next)
       if_block = NULL;
+    else if (else_block == if_block->next)
+      else_block = NULL;
     /* if other blocks reference the blocks, bail, there's loops involved */
     if ((else_block && else_block->incoming > 1) ||
 	(if_block && if_block->incoming > 1))
commit 7ef6c74749037ffe94aaf7c2bc96744aa196655a
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 21:15:13 2008 +0100

    merge if commands

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 1aa5ce3..62b7795 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -613,14 +613,18 @@ error:
 
 static void
 vivi_decompiler_block_append_block (ViviDecompilerBlock *block, 
-    ViviDecompilerBlock *append, const char *prefix)
+    ViviDecompilerBlock *append, gboolean indent)
 {
   guint i;
 
+  if (indent && append->lines->len > 1)
+    vivi_decompiler_block_emit_line (block, NULL, "{");
   for (i = 0; i < append->lines->len; i++) {
-    vivi_decompiler_block_emit_line (block, NULL, "%s%s", 
-	prefix, (char *) g_ptr_array_index (append->lines, i));
+    vivi_decompiler_block_emit_line (block, NULL, "%s%s", indent ? "  " : "",
+	(char *) g_ptr_array_index (append->lines, i));
   }
+  if (indent && append->lines->len > 1)
+    vivi_decompiler_block_emit_line (block, NULL, "}");
 }
 
 static ViviDecompilerBlock *
@@ -655,7 +659,7 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
       vivi_decompiler_block_emit_line (block, NULL, "%s:", 
 	  vivi_decompiler_block_get_label (current));
     }
-    vivi_decompiler_block_append_block (block, current, "");
+    vivi_decompiler_block_append_block (block, current, FALSE);
     if (current->branch) {
       vivi_decompiler_block_emit_line (block, NULL, "  goto %s;",
 	  vivi_decompiler_block_get_label (current->branch));
@@ -683,8 +687,88 @@ vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
 }
 
 static void
+vivi_decompiler_purge_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
+{
+  g_assert (block->incoming == 0);
+  dec->blocks = g_list_remove (dec->blocks, block);
+  if (block->next)
+    block->next->incoming--;
+  if (block->branch)
+    block->branch->incoming--;
+  vivi_decompiler_block_free (block);
+}
+
+static gboolean
+vivi_decompiler_merge_if (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block, *if_block, *else_block;
+  gboolean result;
+  GList *walk;
+
+  result = FALSE;
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    block = walk->data;
+    /* not an if block */
+    if (block->branch == NULL)
+      continue;
+    else_block = block->next;
+    if_block = block->branch;
+    /* if in if in if in if... */
+    if (else_block->branch || if_block->branch)
+      continue;
+    /* one of the blocks doesn't exist */
+    if (if_block == else_block->next)
+      else_block = NULL;
+    else if (else_block == if_block->next)
+      if_block = NULL;
+    /* if other blocks reference the blocks, bail, there's loops involved */
+    if ((else_block && else_block->incoming > 1) ||
+	(if_block && if_block->incoming > 1))
+      continue;
+    /* if both blocks exist, they must have the same exit block */
+    if (if_block && else_block && if_block->next != else_block->next)
+      continue;
+
+    /* FINALLY we can merge the blocks */
+    block->branch = NULL;
+    if (if_block) {
+      vivi_decompiler_block_append_block (block, if_block, TRUE);
+      block->next = if_block->next;
+      if (block->next)
+	block->next->incoming++;
+      if_block->incoming--;
+      vivi_decompiler_purge_block (dec, if_block);
+    } else {
+      vivi_decompiler_block_emit_line (block, NULL, "  ;");
+      block->next = NULL;
+    }
+    if (else_block) {
+      vivi_decompiler_block_emit_line (block, NULL, "else");
+      vivi_decompiler_block_append_block (block, else_block, TRUE);
+      if (block->next == NULL) {
+	block->next = else_block->next;
+	if (block->next)
+	  block->next->incoming++;
+      }
+      else_block->incoming--;
+      vivi_decompiler_purge_block (dec, else_block);
+    }
+    result = TRUE;
+  }
+
+  return result;
+}
+
+static void
 vivi_decompiler_merge_blocks (ViviDecompiler *dec)
 {
+  gboolean restart;
+
+  do {
+    restart = FALSE;
+
+    restart |= vivi_decompiler_merge_if (dec);
+  } while (restart);
   vivi_decompiler_merge_blocks_last_resort (dec);
 }
 
commit fd94d337dbcd507bbba1612a84d1bf6163c4687a
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 20:49:15 2008 +0100

    handle splitting blocks correctly

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index f5aa65a..1aa5ce3 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -167,7 +167,7 @@ struct _ViviDecompilerBlock {
   ViviDecompilerState *	start;		/* starting state */
   GPtrArray *		lines;		/* lines parsed from this block */
   ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
-  ViviDecompilerBlock *	branch;	/* NULL or block branched to i if statement */
+  ViviDecompilerBlock *	branch;		/* NULL or block branched to i if statement */
   /* parsing state */
   guint			incoming;	/* number of incoming blocks */
   const guint8 *	exitpc;		/* pointer to after last parsed command or NULL if not parsed yet */
@@ -175,8 +175,23 @@ struct _ViviDecompilerBlock {
 };
 
 static void
+vivi_decompiler_block_unparse (ViviDecompilerBlock *block)
+{
+  guint i;
+
+  for (i = 0; i < block->lines->len; i++) {
+    g_free (g_ptr_array_index (block->lines, i));
+  }
+  g_ptr_array_set_size (block->lines, 0);
+  block->next = NULL;
+  block->branch = NULL;
+  block->exitpc = NULL;
+}
+
+static void
 vivi_decompiler_block_free (ViviDecompilerBlock *block)
 {
+  vivi_decompiler_block_unparse (block);
   vivi_decompiler_state_free (block->start);
   g_ptr_array_free (block->lines, TRUE);
   g_free (block->label);
@@ -252,12 +267,13 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
     if (block->start->pc < state->pc)
       continue;
     if (block->exitpc && block->exitpc > state->pc) {
-      g_printerr ("FIXME: handle splitting of blocks\n");
-      return NULL;
+      vivi_decompiler_block_unparse (block);
+      break;
     }
     if (block->start->pc == state->pc) {
       g_printerr ("FIXME: check that the blocks are equal\n");
       block->incoming++;
+      vivi_decompiler_state_free (state);
       return block;
     }
     break;
@@ -540,15 +556,25 @@ static void
 vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block)
 {
   ViviDecompilerState *state;
-  const guint8 *start, *end;
+  ViviDecompilerBlock *next_block;
+  GList *list;
+  const guint8 *start, *end, *exit;
   const guint8 *data;
   guint code, len;
 
   start = dec->script->buffer->data;
   end = start + dec->script->buffer->length;
   state = vivi_decompiler_state_copy (block->start);
+  exit = dec->script->exit;
+  list = g_list_find (dec->blocks, block);
+  if (list->next) {
+    next_block = list->next->data;
+    exit = next_block->start->pc;
+  } else {
+    next_block = NULL;
+  }
 
-  while (state->pc != dec->script->exit) {
+  while (state->pc != exit) {
     code = state->pc[0];
     if (code & 0x80) {
       if (state->pc + 2 >= end) {
@@ -566,13 +592,18 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
       len = 0;
     }
     if (!vivi_decompiler_process (dec, block, state, code, data, len))
-      goto error;
+      goto out;
     if (state->pc < start || state->pc >= end) {
       vivi_decompiler_block_emit_error (block, state, "program counter out of range");
       goto error;
     }
   }
+  if (next_block) {
+    block->next = next_block;
+    next_block->incoming++;
+  }
 
+out:
 error:
   block->exitpc = state->pc;
   vivi_decompiler_state_free (state);
commit eb96045ffeb4e009ab4428470f77eabfe7b2290d
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 20:33:13 2008 +0100

    We now handle ifs and jumps

diff --git a/swfdec/swfdec_script.c b/swfdec/swfdec_script.c
index 852b799..b8e0f38 100644
--- a/swfdec/swfdec_script.c
+++ b/swfdec/swfdec_script.c
@@ -77,6 +77,22 @@ swfdec_constant_pool_new_from_action (const guint8 *data, guint len, guint versi
   return pool;
 }
 
+SwfdecConstantPool *
+swfdec_constant_pool_copy (SwfdecConstantPool *pool)
+{
+  SwfdecConstantPool *new;
+  guint i;
+
+  g_return_val_if_fail (pool != NULL, NULL);
+
+  new = g_malloc0 (sizeof (SwfdecConstantPool) + (pool->n_strings - 1) * sizeof (char *));
+  new->n_strings = pool->n_strings;
+  for (i = 0; i < pool->n_strings; i++) {
+    new->strings[i] = g_strdup (pool->strings[i]);
+  }
+  return new;
+}
+
 void
 swfdec_constant_pool_attach_to_context (SwfdecConstantPool *pool, SwfdecAsContext *context)
 {
diff --git a/swfdec/swfdec_script_internal.h b/swfdec/swfdec_script_internal.h
index 8dc4308..4ed473a 100644
--- a/swfdec/swfdec_script_internal.h
+++ b/swfdec/swfdec_script_internal.h
@@ -73,6 +73,8 @@ SwfdecConstantPool *
 							 guint			len,
 							 guint			version);
 void		swfdec_constant_pool_free	  	(SwfdecConstantPool *	pool);
+SwfdecConstantPool *
+		swfdec_constant_pool_copy		(SwfdecConstantPool *	pool);
 guint		swfdec_constant_pool_size		(SwfdecConstantPool *	pool);
 const char *	swfdec_constant_pool_get		(SwfdecConstantPool *	pool,
 							 guint			i);
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index fdfcd0b..f5aa65a 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -145,6 +145,8 @@ vivi_decompiler_state_copy (const ViviDecompilerState *src)
 	&g_array_index (src->stack, ViviDecompilerValue, i));
     vivi_decompiler_state_push (dest, &val);
   }
+  if (src->pool)
+    dest->pool = swfdec_constant_pool_copy (src->pool);
 
   return dest;
 }
@@ -167,6 +169,7 @@ struct _ViviDecompilerBlock {
   ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
   ViviDecompilerBlock *	branch;	/* NULL or block branched to i if statement */
   /* parsing state */
+  guint			incoming;	/* number of incoming blocks */
   const guint8 *	exitpc;		/* pointer to after last parsed command or NULL if not parsed yet */
   char *		label;		/* label generated for this block, so we can goto it */
 };
@@ -192,6 +195,16 @@ vivi_decompiler_block_new (ViviDecompilerState *state)
   return block;
 }
 
+static const char *
+vivi_decompiler_block_get_label (ViviDecompilerBlock *block)
+{
+  /* NB: lael must be unique */
+  if (block->label == NULL)
+    block->label = g_strdup_printf ("label_%p", block->start->pc);
+
+  return block->label;
+}
+
 static void
 vivi_decompiler_block_emit_error (ViviDecompilerBlock *block, ViviDecompilerState *state,
     const char *format, ...) G_GNUC_PRINTF (3, 4);
@@ -244,6 +257,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
     }
     if (block->start->pc == state->pc) {
       g_printerr ("FIXME: check that the blocks are equal\n");
+      block->incoming++;
       return block;
     }
     break;
@@ -251,6 +265,7 @@ vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *
 
   /* FIXME: see if the block is already there! */
   block = vivi_decompiler_block_new (state);
+  block->incoming++;
   dec->blocks = g_list_insert_before (dec->blocks, walk, block);
   return block;
 }
@@ -505,7 +520,6 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	block->next = vivi_decompiler_push_block_for_state (dec, new);
 	return FALSE;
       }
-      break;
     default:
       if (decompile_funcs[code]) {
 	return decompile_funcs[code] (block, state, code, data, len);
@@ -532,11 +546,7 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
 
   start = dec->script->buffer->data;
   end = start + dec->script->buffer->length;
-  state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
-  if (dec->script->constant_pool) {
-    state->pool = swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
-	dec->script->constant_pool->length, dec->script->version);
-  }
+  state = vivi_decompiler_state_copy (block->start);
 
   while (state->pc != dec->script->exit) {
     code = state->pc[0];
@@ -568,6 +578,85 @@ error:
   vivi_decompiler_state_free (state);
 }
 
+/*** PROGRAM STRUCTURE ANALYSIS ***/
+
+static void
+vivi_decompiler_block_append_block (ViviDecompilerBlock *block, 
+    ViviDecompilerBlock *append, const char *prefix)
+{
+  guint i;
+
+  for (i = 0; i < append->lines->len; i++) {
+    vivi_decompiler_block_emit_line (block, NULL, "%s%s", 
+	prefix, (char *) g_ptr_array_index (append->lines, i));
+  }
+}
+
+static ViviDecompilerBlock *
+vivi_decompiler_find_start_block (ViviDecompiler *dec)
+{
+  GList *walk;
+  
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    ViviDecompilerBlock *block = walk->data;
+
+    if (block->start->pc == dec->script->main)
+      return block;
+  }
+  g_assert_not_reached ();
+  return NULL;
+}
+
+static void
+vivi_decompiler_merge_blocks_last_resort (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block, *current, *next;
+  GList *all_blocks;
+
+  current = vivi_decompiler_find_start_block (dec);
+  block = vivi_decompiler_block_new (vivi_decompiler_state_copy (current->start));
+
+  all_blocks = g_list_copy (dec->blocks);
+  while (current) {
+    g_assert (g_list_find (dec->blocks, current));
+    dec->blocks = g_list_remove (dec->blocks, current);
+    if (current->incoming) {
+      vivi_decompiler_block_emit_line (block, NULL, "%s:", 
+	  vivi_decompiler_block_get_label (current));
+    }
+    vivi_decompiler_block_append_block (block, current, "");
+    if (current->branch) {
+      vivi_decompiler_block_emit_line (block, NULL, "  goto %s;",
+	  vivi_decompiler_block_get_label (current->branch));
+    }
+    next = current->next;
+    if (next == NULL || !g_list_find (dec->blocks, next))
+      next = dec->blocks ? dec->blocks->data : NULL;
+    if (current->next == NULL) {
+      if (next)
+	vivi_decompiler_block_emit_line (block, NULL, "return;");
+    } else {
+      if (next == current->next) {
+	next->incoming--;
+      } else {
+	vivi_decompiler_block_emit_line (block, NULL, "goto %s;", 
+	    vivi_decompiler_block_get_label (current->next));
+      }
+    }
+    current = next;
+  }
+  g_list_foreach (all_blocks, (GFunc) vivi_decompiler_block_free, NULL);
+  g_list_free (all_blocks);
+  g_assert (dec->blocks == NULL);
+  dec->blocks = g_list_prepend (dec->blocks, block);
+}
+
+static void
+vivi_decompiler_merge_blocks (ViviDecompiler *dec)
+{
+  vivi_decompiler_merge_blocks_last_resort (dec);
+}
+
 static void
 vivi_decompiler_run (ViviDecompiler *dec)
 {
@@ -576,6 +665,10 @@ vivi_decompiler_run (ViviDecompiler *dec)
   GList *walk;
 
   state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
+  if (dec->script->constant_pool) {
+    state->pool = swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
+	dec->script->constant_pool->length, dec->script->version);
+  }
   block = vivi_decompiler_block_new (state);
   state = vivi_decompiler_state_copy (state);
   g_assert (dec->blocks == NULL);
@@ -590,6 +683,8 @@ vivi_decompiler_run (ViviDecompiler *dec)
       break;
     vivi_decompiler_block_decompile (dec, block);
   }
+
+  vivi_decompiler_merge_blocks (dec);
 }
 
 /*** OBJECT ***/
commit a742b5cca19ef652d37bd12057403ad6a703895c
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 19:45:25 2008 +0100

    handle if block

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 9e449ee..fdfcd0b 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -165,7 +165,7 @@ struct _ViviDecompilerBlock {
   ViviDecompilerState *	start;		/* starting state */
   GPtrArray *		lines;		/* lines parsed from this block */
   ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
-  ViviDecompilerBlock *	if_block;	/* NULL or block branched to i if statement */
+  ViviDecompilerBlock *	branch;	/* NULL or block branched to i if statement */
   /* parsing state */
   const guint8 *	exitpc;		/* pointer to after last parsed command or NULL if not parsed yet */
   char *		label;		/* label generated for this block, so we can goto it */
@@ -467,6 +467,28 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
     ViviDecompilerState *state, guint code, const guint8 *data, guint len)
 {
   switch (code) {
+    case SWFDEC_AS_ACTION_IF:
+      {
+	ViviDecompilerValue val;
+	ViviDecompilerState *new;
+	gint16 offset;
+
+	if (len != 2) {
+	  vivi_decompiler_block_emit_error (block, state, "If action length invalid (is %u, should be 2)", len);
+	  return FALSE;
+	}
+	offset = data[0] | (data[1] << 8);
+	state->pc += 5;
+	vivi_decompiler_state_pop (state, &val);
+	vivi_decompiler_block_emit_line (block, state, "if (%s)", vivi_decompiler_value_get (&val));
+	vivi_decompiler_value_reset (&val);
+	new = vivi_decompiler_state_copy (state);
+	block->next = vivi_decompiler_push_block_for_state (dec, new);
+	new = vivi_decompiler_state_copy (state);
+	new->pc += offset;
+	block->branch = vivi_decompiler_push_block_for_state (dec, new);
+	return FALSE;
+      }
     case SWFDEC_AS_ACTION_JUMP:
       {
 	ViviDecompilerState *new;
commit 18d0e7bbf919169e1a6e66915c571a2904c88269
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 19:40:24 2008 +0100

    avoid duplication of blocks

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 4cc29d8..9e449ee 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -167,7 +167,7 @@ struct _ViviDecompilerBlock {
   ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
   ViviDecompilerBlock *	if_block;	/* NULL or block branched to i if statement */
   /* parsing state */
-  gboolean		finished;	/* TRUE if this block has been parsed already */
+  const guint8 *	exitpc;		/* pointer to after last parsed command or NULL if not parsed yet */
   char *		label;		/* label generated for this block, so we can goto it */
 };
 
@@ -228,20 +228,31 @@ vivi_decompiler_block_emit_line (ViviDecompilerBlock *block, ViviDecompilerState
   g_ptr_array_add (block->lines, s);
 }
 
-static void
-vivi_decompiler_push_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
-{
-  dec->blocks = g_list_prepend (dec->blocks, block);
-}
-
-static void
+static ViviDecompilerBlock *
 vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *state)
 {
   ViviDecompilerBlock *block;
+  GList *walk;
+
+  for (walk = dec->blocks; walk; walk = walk->next) {
+    block = walk->data;
+    if (block->start->pc < state->pc)
+      continue;
+    if (block->exitpc && block->exitpc > state->pc) {
+      g_printerr ("FIXME: handle splitting of blocks\n");
+      return NULL;
+    }
+    if (block->start->pc == state->pc) {
+      g_printerr ("FIXME: check that the blocks are equal\n");
+      return block;
+    }
+    break;
+  }
 
   /* FIXME: see if the block is already there! */
   block = vivi_decompiler_block_new (state);
-  vivi_decompiler_push_block (dec, block);
+  dec->blocks = g_list_insert_before (dec->blocks, walk, block);
+  return block;
 }
 
 /*** BYTECODE DECOMPILER ***/
@@ -456,7 +467,6 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
     ViviDecompilerState *state, guint code, const guint8 *data, guint len)
 {
   switch (code) {
-    case SWFDEC_AS_ACTION_IF:
     case SWFDEC_AS_ACTION_JUMP:
       {
 	ViviDecompilerState *new;
@@ -470,7 +480,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block,
 	state->pc += 5;
 	new = vivi_decompiler_state_copy (state);
 	new->pc += offset;
-	vivi_decompiler_push_block_for_state (dec, new);
+	block->next = vivi_decompiler_push_block_for_state (dec, new);
 	return FALSE;
       }
       break;
@@ -532,8 +542,8 @@ vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block
   }
 
 error:
+  block->exitpc = state->pc;
   vivi_decompiler_state_free (state);
-  block->finished = TRUE;
 }
 
 static void
@@ -546,11 +556,12 @@ vivi_decompiler_run (ViviDecompiler *dec)
   state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
   block = vivi_decompiler_block_new (state);
   state = vivi_decompiler_state_copy (state);
-  vivi_decompiler_push_block (dec, block);
+  g_assert (dec->blocks == NULL);
+  dec->blocks = g_list_prepend (dec->blocks, block);
   while (TRUE) {
     for (walk = dec->blocks; walk; walk = walk->next) {
       block = walk->data;
-      if (!block->finished)
+      if (block->exitpc == NULL)
 	break;
     }
     if (walk == NULL)
commit 4f9cf705eb918e3913d8e77bb726571e54b7d5bd
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 17:47:53 2008 +0100

    introduce blocks

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index b5ae6c4..4cc29d8 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -52,8 +52,15 @@ vivi_decompiler_value_copy (ViviDecompilerValue *dest, const ViviDecompilerValue
   dest->unconstant = src->unconstant;
 }
 
+static const char * 
+vivi_decompiler_value_get (const ViviDecompilerValue *value)
+{
+  return value->value ? value->value : "undefined";
+}
+
 typedef struct _ViviDecompilerState ViviDecompilerState;
 struct _ViviDecompilerState {
+  SwfdecScript *	script;
   const guint8 *	pc;
   ViviDecompilerValue *	registers;
   guint			n_registers;
@@ -77,14 +84,16 @@ vivi_decompiler_state_free (ViviDecompilerState *state)
     swfdec_constant_pool_free (state->pool);
   g_array_free (state->stack, TRUE);
   g_slice_free1 (sizeof (ViviDecompilerValue) * state->n_registers, state->registers);
+  swfdec_script_unref (state->script);
   g_slice_free (ViviDecompilerState, state);
 }
 
 static ViviDecompilerState *
-vivi_decompiler_state_new (const guint8 *pc, guint n_registers)
+vivi_decompiler_state_new (SwfdecScript *script, const guint8 *pc, guint n_registers)
 {
   ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
 
+  state->script = swfdec_script_ref (script);
   state->pc = pc;
   state->registers = g_slice_alloc0 (sizeof (ViviDecompilerValue) * n_registers);
   state->n_registers = n_registers;
@@ -94,12 +103,12 @@ vivi_decompiler_state_new (const guint8 *pc, guint n_registers)
 }
 
 static void
-vivi_decompiler_state_push (ViviDecompilerState *state, const ViviDecompilerValue *val)
+vivi_decompiler_state_push (ViviDecompilerState *state, ViviDecompilerValue *val)
 {
   g_array_append_val (state->stack, *val);
 }
 
-static const ViviDecompilerValue undefined = { (char *) "undefined", FALSE };
+static const ViviDecompilerValue undefined = { NULL, FALSE };
 
 static void
 vivi_decompiler_state_pop (ViviDecompilerState *state, ViviDecompilerValue *val)
@@ -119,6 +128,27 @@ vivi_decompiler_state_pop (ViviDecompilerState *state, ViviDecompilerValue *val)
   g_array_set_size (state->stack, state->stack->len - 1);
 }
 
+static ViviDecompilerState *
+vivi_decompiler_state_copy (const ViviDecompilerState *src)
+{
+  ViviDecompilerState *dest;
+  guint i;
+
+  dest = vivi_decompiler_state_new (src->script, src->pc, src->n_registers);
+  for (i = 0; i < src->n_registers; i++) {
+    if (src->registers[i].value)
+      vivi_decompiler_value_copy (&dest->registers[i], &src->registers[i]);
+  }
+  for (i = 0; i < src->stack->len; i++) {
+    ViviDecompilerValue val = { NULL, };
+    vivi_decompiler_value_copy (&val, 
+	&g_array_index (src->stack, ViviDecompilerValue, i));
+    vivi_decompiler_state_push (dest, &val);
+  }
+
+  return dest;
+}
+
 static const ViviDecompilerValue *
 vivi_decompiler_state_get_register (ViviDecompilerState *state, guint reg)
 {
@@ -128,11 +158,45 @@ vivi_decompiler_state_get_register (ViviDecompilerState *state, guint reg)
     return &state->registers[state->n_registers];
 }
 
+/*** BLOCK ***/
+
+typedef struct _ViviDecompilerBlock ViviDecompilerBlock;
+struct _ViviDecompilerBlock {
+  ViviDecompilerState *	start;		/* starting state */
+  GPtrArray *		lines;		/* lines parsed from this block */
+  ViviDecompilerBlock *	next;		/* block following this one or NULL if returning */
+  ViviDecompilerBlock *	if_block;	/* NULL or block branched to i if statement */
+  /* parsing state */
+  gboolean		finished;	/* TRUE if this block has been parsed already */
+  char *		label;		/* label generated for this block, so we can goto it */
+};
+
 static void
-vivi_decompiler_emit_error (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompiler_block_free (ViviDecompilerBlock *block)
+{
+  vivi_decompiler_state_free (block->start);
+  g_ptr_array_free (block->lines, TRUE);
+  g_free (block->label);
+  g_slice_free (ViviDecompilerBlock, block);
+}
+
+static ViviDecompilerBlock *
+vivi_decompiler_block_new (ViviDecompilerState *state)
+{
+  ViviDecompilerBlock *block;
+
+  block = g_slice_new0 (ViviDecompilerBlock);
+  block->start = state;
+  block->lines = g_ptr_array_new ();
+
+  return block;
+}
+
+static void
+vivi_decompiler_block_emit_error (ViviDecompilerBlock *block, ViviDecompilerState *state,
     const char *format, ...) G_GNUC_PRINTF (3, 4);
 static void
-vivi_decompiler_emit_error (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompiler_block_emit_error (ViviDecompilerBlock *block, ViviDecompilerState *state,
     const char *format, ...)
 {
   va_list varargs;
@@ -144,14 +208,14 @@ vivi_decompiler_emit_error (ViviDecompiler *dec, ViviDecompilerState *state,
   t = g_strdup_printf ("/* %s */", s);
   g_free (s);
 
-  g_ptr_array_add (dec->lines, t);
+  g_ptr_array_add (block->lines, t);
 }
 
 static void
-vivi_decompiler_emit_line (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompiler_block_emit_line (ViviDecompilerBlock *block, ViviDecompilerState *state,
     const char *format, ...) G_GNUC_PRINTF (3, 4);
 static void
-vivi_decompiler_emit_line (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompiler_block_emit_line (ViviDecompilerBlock *block, ViviDecompilerState *state,
     const char *format, ...)
 {
   va_list varargs;
@@ -161,12 +225,28 @@ vivi_decompiler_emit_line (ViviDecompiler *dec, ViviDecompilerState *state,
   s = g_strdup_vprintf (format, varargs);
   va_end (varargs);
 
-  g_ptr_array_add (dec->lines, s);
+  g_ptr_array_add (block->lines, s);
+}
+
+static void
+vivi_decompiler_push_block (ViviDecompiler *dec, ViviDecompilerBlock *block)
+{
+  dec->blocks = g_list_prepend (dec->blocks, block);
+}
+
+static void
+vivi_decompiler_push_block_for_state (ViviDecompiler *dec, ViviDecompilerState *state)
+{
+  ViviDecompilerBlock *block;
+
+  /* FIXME: see if the block is already there! */
+  block = vivi_decompiler_block_new (state);
+  vivi_decompiler_push_block (dec, block);
 }
 
 /*** BYTECODE DECOMPILER ***/
 
-typedef gboolean (* DecompileFunc) (ViviDecompiler *dec, ViviDecompilerState *state,
+typedef gboolean (* DecompileFunc) (ViviDecompilerBlock *block, ViviDecompilerState *state,
           guint code, const guint8 *data, guint len);
 
 static char *
@@ -196,7 +276,7 @@ escape_string (const char *s)
 }
 
 static gboolean
-vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompile_push (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
   ViviDecompilerValue val;
@@ -210,9 +290,11 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
     switch (type) {
       case 0: /* string */
 	{
-	  char *s = swfdec_bits_get_string (&bits, dec->script->version);
-	  if (s == NULL)
+	  char *s = swfdec_bits_get_string (&bits, state->script->version);
+	  if (s == NULL) {
+	    vivi_decompiler_block_emit_error (block, state, "could not read string");
 	    return FALSE;
+	  }
 	  val.value = escape_string (s);
 	  g_free (s);
 	  break;
@@ -224,7 +306,6 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 	val.value = g_strdup ("null");
 	break;
       case 3: /* undefined */
-	val.value = g_strdup ("undefined");
 	break;
       case 4: /* register */
 	{
@@ -246,11 +327,11 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 	{
 	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
 	  if (state->pool == NULL) {
-	    vivi_decompiler_emit_error (dec, state,"no constant pool to push from");
+	    vivi_decompiler_block_emit_error (block, state, "no constant pool to push from");
 	    return FALSE;
 	  }
 	  if (i >= swfdec_constant_pool_size (state->pool)) {
-	    vivi_decompiler_emit_error (dec, state,"constant pool index %u too high - only %u elements",
+	    vivi_decompiler_block_emit_error (block, state, "constant pool index %u too high - only %u elements",
 		i, swfdec_constant_pool_size (state->pool));
 	    return FALSE;
 	  }
@@ -258,7 +339,7 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 	  break;
 	}
       default:
-	vivi_decompiler_emit_error (dec, state,"Push: type %u not implemented", type);
+	vivi_decompiler_block_emit_error (block, state, "Push: type %u not implemented", type);
 	return FALSE;
     }
     vivi_decompiler_state_push (state, &val);
@@ -269,54 +350,52 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 }
 
 static gboolean
-vivi_decompile_pop (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompile_pop (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
   ViviDecompilerValue val;
   
   vivi_decompiler_state_pop (state, &val);
   state->pc++;
-  vivi_decompiler_emit_line (dec, state, "%s;", val.value);
+  vivi_decompiler_block_emit_line (block, state, "%s;", vivi_decompiler_value_get (&val));
   vivi_decompiler_value_reset (&val);
   return TRUE;
 }
 
 static gboolean
-vivi_decompile_constant_pool (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompile_constant_pool (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
   if (state->pool)
     swfdec_constant_pool_free (state->pool);
 
-  state->pool = swfdec_constant_pool_new_from_action (data, len, dec->script->version);
+  state->pool = swfdec_constant_pool_new_from_action (data, len, state->script->version);
   state->pc = data + len;
   return TRUE;
 }
 
 static gboolean
-vivi_decompile_trace (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompile_trace (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
   ViviDecompilerValue val;
   
   vivi_decompiler_state_pop (state, &val);
   state->pc++;
-  vivi_decompiler_emit_line (dec, state, "trace (%s);", val.value);
+  vivi_decompiler_block_emit_line (block, state, "trace (%s);", vivi_decompiler_value_get (&val));
   vivi_decompiler_value_reset (&val);
   return TRUE;
 }
 
 static gboolean
-vivi_decompile_end (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompile_end (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
-  state->pc = dec->script->exit;
-  vivi_decompiler_emit_line (dec, state, "return;");
-  return TRUE;
+  return FALSE;
 }
 
 static gboolean
-vivi_decompile_get_url2 (ViviDecompiler *dec, ViviDecompilerState *state,
+vivi_decompile_get_url2 (ViviDecompilerBlock *block, ViviDecompilerState *state,
     guint code, const guint8 *data, guint len)
 {
   ViviDecompilerValue url, target;
@@ -327,13 +406,13 @@ vivi_decompile_get_url2 (ViviDecompiler *dec, ViviDecompilerState *state,
 
   state->pc = data + len;
   if (len != 1) {
-    vivi_decompiler_emit_error (dec, state, "invalid getURL2 command");   
+    vivi_decompiler_block_emit_error (block, state, "invalid length in getURL2 command");   
   } else {
     guint method = data[0] & 3;
     guint internal = data[0] & 64;
     guint variables = data[0] & 128;
     if (method == 3) {
-      vivi_decompiler_emit_error (dec, state, "GetURL method 3 invalid");
+      vivi_decompiler_block_emit_error (block, state, "GetURL method 3 invalid");
       method = 0;
     }
 
@@ -344,11 +423,16 @@ vivi_decompile_get_url2 (ViviDecompiler *dec, ViviDecompilerState *state,
     } else {
       fun = "getURL";
     }
-    if (method == 0)
-      vivi_decompiler_emit_line (dec, state, "%s (%s, %s);", fun, url.value, target.value);
-    else
-      vivi_decompiler_emit_line (dec, state, "%s (%s, %s, %s);", 
-	  fun, url.value, target.value, method == 1 ? "\"GET\"" : "\"POST\"");
+    if (method == 0) {
+      vivi_decompiler_block_emit_line (block, state, "%s (%s, %s);", fun, 
+	  vivi_decompiler_value_get (&url),
+	  vivi_decompiler_value_get (&target));
+    } else {
+      vivi_decompiler_block_emit_line (block, state, "%s (%s, %s, %s);", fun,
+	  vivi_decompiler_value_get (&url),
+	  vivi_decompiler_value_get (&target),
+	  method == 1 ? "\"GET\"" : "\"POST\"");
+    }
   }
   vivi_decompiler_value_reset (&url);
   vivi_decompiler_value_reset (&target);
@@ -362,20 +446,44 @@ static DecompileFunc decompile_funcs[256] = {
 
   [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
   [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
+  [SWFDEC_AS_ACTION_JUMP] = NULL, /* handled directly */
   [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
+  [SWFDEC_AS_ACTION_IF] = NULL, /* handled directly */
 };
 
 static gboolean
-vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerState *state,
-    guint code, const guint8 *data, guint len)
+vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerBlock *block, 
+    ViviDecompilerState *state, guint code, const guint8 *data, guint len)
 {
   switch (code) {
+    case SWFDEC_AS_ACTION_IF:
+    case SWFDEC_AS_ACTION_JUMP:
+      {
+	ViviDecompilerState *new;
+	gint16 offset;
+
+	if (len != 2) {
+	  vivi_decompiler_block_emit_error (block, state, "Jump action length invalid (is %u, should be 2)", len);
+	  return FALSE;
+	}
+	offset = data[0] | (data[1] << 8);
+	state->pc += 5;
+	new = vivi_decompiler_state_copy (state);
+	new->pc += offset;
+	vivi_decompiler_push_block_for_state (dec, new);
+	return FALSE;
+      }
+      break;
     default:
       if (decompile_funcs[code]) {
-	return decompile_funcs[code] (dec, state, code, data, len);
+	return decompile_funcs[code] (block, state, code, data, len);
       } else {
-	vivi_decompiler_emit_error (dec, state,"unknown bytecode 0x%02X %u", code, code);
-	return FALSE;
+	vivi_decompiler_block_emit_error (block, state, "unknown bytecode 0x%02X %u", code, code);
+	if (data)
+	  state->pc = data + len;
+	else
+	  state->pc++;
+	break;
       }
   };
 
@@ -383,7 +491,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerState *state,
 }
 
 static void
-vivi_decompiler_run (ViviDecompiler *dec)
+vivi_decompiler_block_decompile (ViviDecompiler *dec, ViviDecompilerBlock *block)
 {
   ViviDecompilerState *state;
   const guint8 *start, *end;
@@ -392,7 +500,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
 
   start = dec->script->buffer->data;
   end = start + dec->script->buffer->length;
-  state = vivi_decompiler_state_new (dec->script->main, 4);
+  state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
   if (dec->script->constant_pool) {
     state->pool = swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
 	dec->script->constant_pool->length, dec->script->version);
@@ -402,29 +510,53 @@ vivi_decompiler_run (ViviDecompiler *dec)
     code = state->pc[0];
     if (code & 0x80) {
       if (state->pc + 2 >= end) {
-	vivi_decompiler_emit_error (dec, state,"bytecode %u length value out of range", code);
+	vivi_decompiler_block_emit_error (block, state, "bytecode %u length value out of range", code);
 	goto error;
       }
       data = state->pc + 3;
       len = state->pc[1] | state->pc[2] << 8;
       if (data + len > end) {
-	vivi_decompiler_emit_error (dec, state,"bytecode %u length %u out of range", code, len);
+	vivi_decompiler_block_emit_error (block, state, "bytecode %u length %u out of range", code, len);
 	goto error;
       }
     } else {
       data = NULL;
       len = 0;
     }
-    if (!vivi_decompiler_process (dec, state, code, data, len))
+    if (!vivi_decompiler_process (dec, block, state, code, data, len))
       goto error;
     if (state->pc < start || state->pc >= end) {
-      vivi_decompiler_emit_error (dec, state,"program counter out of range");
+      vivi_decompiler_block_emit_error (block, state, "program counter out of range");
       goto error;
     }
   }
 
 error:
   vivi_decompiler_state_free (state);
+  block->finished = TRUE;
+}
+
+static void
+vivi_decompiler_run (ViviDecompiler *dec)
+{
+  ViviDecompilerBlock *block;
+  ViviDecompilerState *state;
+  GList *walk;
+
+  state = vivi_decompiler_state_new (dec->script, dec->script->main, 4);
+  block = vivi_decompiler_block_new (state);
+  state = vivi_decompiler_state_copy (state);
+  vivi_decompiler_push_block (dec, block);
+  while (TRUE) {
+    for (walk = dec->blocks; walk; walk = walk->next) {
+      block = walk->data;
+      if (!block->finished)
+	break;
+    }
+    if (walk == NULL)
+      break;
+    vivi_decompiler_block_decompile (dec, block);
+  }
 }
 
 /*** OBJECT ***/
@@ -435,16 +567,14 @@ static void
 vivi_decompiler_dispose (GObject *object)
 {
   ViviDecompiler *dec = VIVI_DECOMPILER (object);
-  guint i;
 
   if (dec->script) {
     swfdec_script_unref (dec->script);
     dec->script = NULL;
   }
-  for (i = 0; i < dec->lines->len; i++) {
-    g_free (&g_ptr_array_index (dec->lines, i));
-  }
-  g_ptr_array_free (dec->lines, TRUE);
+  g_list_foreach (dec->blocks, (GFunc) vivi_decompiler_block_free, NULL);
+  g_list_free (dec->blocks);
+  dec->blocks = NULL;
 
   G_OBJECT_CLASS (vivi_decompiler_parent_class)->dispose (object);
 }
@@ -460,7 +590,6 @@ vivi_decompiler_class_init (ViviDecompilerClass *klass)
 static void
 vivi_decompiler_init (ViviDecompiler *dec)
 {
-  dec->lines = g_ptr_array_new ();
 }
 
 ViviDecompiler *
@@ -477,18 +606,28 @@ vivi_decompiler_new (SwfdecScript *script)
 guint
 vivi_decompiler_get_n_lines (ViviDecompiler *dec)
 {
+  ViviDecompilerBlock *block;
+
   g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), 0);
 
-  return dec->lines->len;
+  if (dec->blocks == NULL)
+    return 0;
+
+  block = dec->blocks->data;
+  return block->lines->len;
 }
 
 const char *
 vivi_decompiler_get_line (ViviDecompiler *dec, guint i)
 {
+  ViviDecompilerBlock *block;
+
   g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
-  g_return_val_if_fail (i < dec->lines->len, NULL);
+  g_return_val_if_fail (dec->blocks != NULL, NULL);
+  block = dec->blocks->data;
+  g_return_val_if_fail (i < block->lines->len, NULL);
 
-  return g_ptr_array_index (dec->lines, i);
+  return g_ptr_array_index (block->lines, i);
 }
 
 
diff --git a/vivified/compiler/vivi_decompiler.h b/vivified/compiler/vivi_decompiler.h
index 0ba52f3..ddc85ac 100644
--- a/vivified/compiler/vivi_decompiler.h
+++ b/vivified/compiler/vivi_decompiler.h
@@ -40,7 +40,7 @@ struct _ViviDecompiler
   SwfdecAsObject	object;
 
   SwfdecScript *	script;
-  GPtrArray *		lines;
+  GList *		blocks;
 };
 
 struct _ViviDecompilerClass
commit 493ad105073c43c3b5efed7858c398d176afa666
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 17:40:10 2008 +0100

    fix error messages

diff --git a/swfdec/swfdec_as_interpret.c b/swfdec/swfdec_as_interpret.c
index ff0a66c..e68b998 100644
--- a/swfdec/swfdec_as_interpret.c
+++ b/swfdec/swfdec_as_interpret.c
@@ -1094,7 +1094,7 @@ swfdec_action_jump (SwfdecAsContext *cx, guint action, const guint8 *data, guint
   gint16 offset;
 
   if (len != 2) {
-    SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
+    SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2)", len);
     return;
   }
   offset = data[0] | (data[1] << 8);
@@ -1105,7 +1105,7 @@ static void
 swfdec_action_if (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
 {
   if (len != 2) {
-    SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
+    SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len);
     return;
   }
   if (swfdec_as_value_to_boolean (cx, swfdec_as_stack_peek (cx, 1))) {
@@ -2967,7 +2967,7 @@ swfdec_action_print_if (guint action, const guint8 *data, guint len)
   gint16 offset;
 
   if (len != 2) {
-    SWFDEC_ERROR ("If action length invalid (is %u, should be 2", len);
+    SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len);
     return NULL;
   }
   offset = data[0] | (data[1] << 8);
@@ -2980,7 +2980,7 @@ swfdec_action_print_jump (guint action, const guint8 *data, guint len)
   gint16 offset;
 
   if (len != 2) {
-    SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
+    SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len);
     return NULL;
   }
   offset = data[0] | (data[1] << 8);
commit 64b7b19cf2efcdefb3cbb6050a2531e298cef409
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 03:18:23 2008 +0100

    more error handling improvements

diff --git a/vivified/compiler/decompiler.c b/vivified/compiler/decompiler.c
index 2325f96..7a3a58b 100644
--- a/vivified/compiler/decompiler.c
+++ b/vivified/compiler/decompiler.c
@@ -64,13 +64,14 @@ main (int argc, char *argv[])
   swfdec_url_free (url);
   /* FIXME: HACK! */
   swfdec_player_advance (player, 0);
-  if (!SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data)) {
+  if (player->priv->roots == NULL ||
+      !SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data) ||
+      (dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder)) == NULL) {
     g_printerr ("Error parsing file \"%s\"\n", argv[1]);
     g_object_unref (player);
     player = NULL;
     return 1;
   }
-  dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder);
 
   g_print ("/* version: %d - size: %ux%u */\n", dec->version,
       player->priv->width, player->priv->height);
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 16f4ed9..b5ae6c4 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -374,7 +374,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerState *state,
       if (decompile_funcs[code]) {
 	return decompile_funcs[code] (dec, state, code, data, len);
       } else {
-	vivi_decompiler_emit_error (dec, state,"unknown bytecode %20X %u", code, code);
+	vivi_decompiler_emit_error (dec, state,"unknown bytecode 0x%02X %u", code, code);
 	return FALSE;
       }
   };
commit 5c9114697fcb4f1603ff944d9b5408bf12a9494c
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 03:11:34 2008 +0100

    fix various bugs

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 7cdf853..16f4ed9 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -73,7 +73,8 @@ vivi_decompiler_state_free (ViviDecompilerState *state)
     vivi_decompiler_value_reset (&g_array_index (state->stack, ViviDecompilerValue, i));
   }
 
-  swfdec_constant_pool_free (state->pool);
+  if (state->pool)
+    swfdec_constant_pool_free (state->pool);
   g_array_free (state->stack, TRUE);
   g_slice_free1 (sizeof (ViviDecompilerValue) * state->n_registers, state->registers);
   g_slice_free (ViviDecompilerState, state);
@@ -249,7 +250,7 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 	    return FALSE;
 	  }
 	  if (i >= swfdec_constant_pool_size (state->pool)) {
-	    vivi_decompiler_emit_error (dec, state,"constant pool index %u too high - only %u elements\n",
+	    vivi_decompiler_emit_error (dec, state,"constant pool index %u too high - only %u elements",
 		i, swfdec_constant_pool_size (state->pool));
 	    return FALSE;
 	  }
@@ -373,7 +374,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerState *state,
       if (decompile_funcs[code]) {
 	return decompile_funcs[code] (dec, state, code, data, len);
       } else {
-	vivi_decompiler_emit_error (dec, state,"unknown bytecode %20X %u\n", code, code);
+	vivi_decompiler_emit_error (dec, state,"unknown bytecode %20X %u", code, code);
 	return FALSE;
       }
   };
commit 8a058184c3acb8e35f22263984e0b0d09ac3410b
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 03:03:05 2008 +0100

    arguments were wrong...

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 110d717..7cdf853 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -321,8 +321,8 @@ vivi_decompile_get_url2 (ViviDecompiler *dec, ViviDecompilerState *state,
   ViviDecompilerValue url, target;
   const char *fun;
 
-  vivi_decompiler_state_pop (state, &url);
   vivi_decompiler_state_pop (state, &target);
+  vivi_decompiler_state_pop (state, &url);
 
   state->pc = data + len;
   if (len != 1) {
commit d1549f55ab7975e7830b1ed43c9f9c076e5d00af
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 03:02:13 2008 +0100

    beautify output

diff --git a/vivified/compiler/decompiler.c b/vivified/compiler/decompiler.c
index d0ed941..2325f96 100644
--- a/vivified/compiler/decompiler.c
+++ b/vivified/compiler/decompiler.c
@@ -37,10 +37,13 @@ decode_script (gpointer offset, gpointer scriptp, gpointer unused)
   ViviDecompiler *dec = vivi_decompiler_new (scriptp);
   guint i;
 
-  g_print ("%s:\n", script->name);
+  g_print ("/* %s */\n", script->name);
+  g_print ("{\n");
   for (i = 0; i < vivi_decompiler_get_n_lines (dec); i++) {
     g_print ("  %s\n", vivi_decompiler_get_line (dec, i));
   }
+  g_print ("}\n");
+  g_print ("\n");
 }
 
 int 
@@ -69,6 +72,9 @@ main (int argc, char *argv[])
   }
   dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder);
 
+  g_print ("/* version: %d - size: %ux%u */\n", dec->version,
+      player->priv->width, player->priv->height);
+  g_print ("\n");
   g_hash_table_foreach (dec->scripts, decode_script, NULL);
 
   g_object_unref (player);
commit 96d69998831fc18293870a08b4a0f59762ef8265
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 02:58:21 2008 +0100

    make all errors do an emit_error

diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 37e2af9..110d717 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -245,11 +245,11 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 	{
 	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
 	  if (state->pool == NULL) {
-	    g_printerr ("no constant pool to push from");
+	    vivi_decompiler_emit_error (dec, state,"no constant pool to push from");
 	    return FALSE;
 	  }
 	  if (i >= swfdec_constant_pool_size (state->pool)) {
-	    g_printerr ("constant pool index %u too high - only %u elements\n",
+	    vivi_decompiler_emit_error (dec, state,"constant pool index %u too high - only %u elements\n",
 		i, swfdec_constant_pool_size (state->pool));
 	    return FALSE;
 	  }
@@ -257,7 +257,7 @@ vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
 	  break;
 	}
       default:
-	g_printerr ("Push: type %u not implemented", type);
+	vivi_decompiler_emit_error (dec, state,"Push: type %u not implemented", type);
 	return FALSE;
     }
     vivi_decompiler_state_push (state, &val);
@@ -373,7 +373,7 @@ vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerState *state,
       if (decompile_funcs[code]) {
 	return decompile_funcs[code] (dec, state, code, data, len);
       } else {
-	g_printerr ("unknown bytecode %20X %u\n", code, code);
+	vivi_decompiler_emit_error (dec, state,"unknown bytecode %20X %u\n", code, code);
 	return FALSE;
       }
   };
@@ -401,13 +401,13 @@ vivi_decompiler_run (ViviDecompiler *dec)
     code = state->pc[0];
     if (code & 0x80) {
       if (state->pc + 2 >= end) {
-	g_printerr ("bytecode %u length value out of range", code);
+	vivi_decompiler_emit_error (dec, state,"bytecode %u length value out of range", code);
 	goto error;
       }
       data = state->pc + 3;
       len = state->pc[1] | state->pc[2] << 8;
       if (data + len > end) {
-	g_printerr ("bytecode %u length %u out of range", code, len);
+	vivi_decompiler_emit_error (dec, state,"bytecode %u length %u out of range", code, len);
 	goto error;
       }
     } else {
@@ -417,7 +417,7 @@ vivi_decompiler_run (ViviDecompiler *dec)
     if (!vivi_decompiler_process (dec, state, code, data, len))
       goto error;
     if (state->pc < start || state->pc >= end) {
-      g_printerr ("program counter out of range");
+      vivi_decompiler_emit_error (dec, state,"program counter out of range");
       goto error;
     }
   }
commit 3e111f45bb996ed1b8e3f4d1cdf2f12991c6e4f9
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 02:57:20 2008 +0100

    make Hello World decompile

diff --git a/swfdec/swfdec_as_interpret.h b/swfdec/swfdec_as_interpret.h
index 09201dd..36f2f3f 100644
--- a/swfdec/swfdec_as_interpret.h
+++ b/swfdec/swfdec_as_interpret.h
@@ -37,6 +37,7 @@ extern const SwfdecActionSpec swfdec_as_actions[256];
 
 /* all known actions */
 typedef enum {
+  SWFDEC_AS_ACTION_END = 0x00,
   SWFDEC_AS_ACTION_NEXT_FRAME = 0x04,
   SWFDEC_AS_ACTION_PREVIOUS_FRAME = 0x05,
   SWFDEC_AS_ACTION_PLAY = 0x06,
diff --git a/vivified/compiler/decompiler.c b/vivified/compiler/decompiler.c
index ad0d7ac..d0ed941 100644
--- a/vivified/compiler/decompiler.c
+++ b/vivified/compiler/decompiler.c
@@ -39,7 +39,7 @@ decode_script (gpointer offset, gpointer scriptp, gpointer unused)
 
   g_print ("%s:\n", script->name);
   for (i = 0; i < vivi_decompiler_get_n_lines (dec); i++) {
-    g_print ("%s  \n", vivi_decompiler_get_line (dec, i));
+    g_print ("  %s\n", vivi_decompiler_get_line (dec, i));
   }
 }
 
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index b35620d..37e2af9 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -21,6 +21,12 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
+#include <swfdec/swfdec_as_interpret.h>
+#include <swfdec/swfdec_bits.h>
+#include <swfdec/swfdec_script_internal.h>
+
 #include "vivi_decompiler.h"
 
 /*** DECOMPILER ENGINE ***/
@@ -36,14 +42,23 @@ vivi_decompiler_value_reset (ViviDecompilerValue *value)
 {
   g_free (value->value);
   value->value = NULL;
-  value->unconstant = TRUE;
+  value->unconstant = FALSE;
+}
+
+static void
+vivi_decompiler_value_copy (ViviDecompilerValue *dest, const ViviDecompilerValue *src)
+{
+  dest->value = g_strdup (src->value);
+  dest->unconstant = src->unconstant;
 }
 
 typedef struct _ViviDecompilerState ViviDecompilerState;
 struct _ViviDecompilerState {
+  const guint8 *	pc;
   ViviDecompilerValue *	registers;
   guint			n_registers;
   GArray *		stack;
+  SwfdecConstantPool *	pool;
 };
 
 static void
@@ -58,16 +73,18 @@ vivi_decompiler_state_free (ViviDecompilerState *state)
     vivi_decompiler_value_reset (&g_array_index (state->stack, ViviDecompilerValue, i));
   }
 
+  swfdec_constant_pool_free (state->pool);
   g_array_free (state->stack, TRUE);
   g_slice_free1 (sizeof (ViviDecompilerValue) * state->n_registers, state->registers);
   g_slice_free (ViviDecompilerState, state);
 }
 
 static ViviDecompilerState *
-vivi_decompiler_state_new (guint n_registers)
+vivi_decompiler_state_new (const guint8 *pc, guint n_registers)
 {
   ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
 
+  state->pc = pc;
   state->registers = g_slice_alloc0 (sizeof (ViviDecompilerValue) * n_registers);
   state->n_registers = n_registers;
   state->stack = g_array_new (FALSE, TRUE, sizeof (ViviDecompilerValue));
@@ -76,10 +93,336 @@ vivi_decompiler_state_new (guint n_registers)
 }
 
 static void
+vivi_decompiler_state_push (ViviDecompilerState *state, const ViviDecompilerValue *val)
+{
+  g_array_append_val (state->stack, *val);
+}
+
+static const ViviDecompilerValue undefined = { (char *) "undefined", FALSE };
+
+static void
+vivi_decompiler_state_pop (ViviDecompilerState *state, ViviDecompilerValue *val)
+{
+  if (state->stack->len == 0) {
+    if (val)
+      *val = undefined;
+  } else {
+    ViviDecompilerValue *pop;
+    pop = &g_array_index (state->stack, ViviDecompilerValue, state->stack->len - 1);
+    if (val)
+      *val = *pop;
+    else
+      vivi_decompiler_value_reset (pop);
+  }
+
+  g_array_set_size (state->stack, state->stack->len - 1);
+}
+
+static const ViviDecompilerValue *
+vivi_decompiler_state_get_register (ViviDecompilerState *state, guint reg)
+{
+  if (reg >= state->n_registers)
+    return &undefined;
+  else
+    return &state->registers[state->n_registers];
+}
+
+static void
+vivi_decompiler_emit_error (ViviDecompiler *dec, ViviDecompilerState *state,
+    const char *format, ...) G_GNUC_PRINTF (3, 4);
+static void
+vivi_decompiler_emit_error (ViviDecompiler *dec, ViviDecompilerState *state,
+    const char *format, ...)
+{
+  va_list varargs;
+  char *s, *t;
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+  t = g_strdup_printf ("/* %s */", s);
+  g_free (s);
+
+  g_ptr_array_add (dec->lines, t);
+}
+
+static void
+vivi_decompiler_emit_line (ViviDecompiler *dec, ViviDecompilerState *state,
+    const char *format, ...) G_GNUC_PRINTF (3, 4);
+static void
+vivi_decompiler_emit_line (ViviDecompiler *dec, ViviDecompilerState *state,
+    const char *format, ...)
+{
+  va_list varargs;
+  char *s;
+
+  va_start (varargs, format);
+  s = g_strdup_vprintf (format, varargs);
+  va_end (varargs);
+
+  g_ptr_array_add (dec->lines, s);
+}
+
+/*** BYTECODE DECOMPILER ***/
+
+typedef gboolean (* DecompileFunc) (ViviDecompiler *dec, ViviDecompilerState *state,
+          guint code, const guint8 *data, guint len);
+
+static char *
+escape_string (const char *s)
+{
+  GString *str;
+  char *next;
+
+  str = g_string_new ("\"");
+  while ((next = strpbrk (s, "\"\n"))) {
+    g_string_append_len (str, s, next - s);
+    switch (*next) {
+      case '"':
+	g_string_append (str, "\"");
+	break;
+      case '\n':
+	g_string_append (str, "\n");
+	break;
+      default:
+	g_assert_not_reached ();
+    }
+    s = next + 1;
+  }
+  g_string_append (str, s);
+  g_string_append_c (str, '"');
+  return g_string_free (str, FALSE);
+}
+
+static gboolean
+vivi_decompile_push (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviDecompilerValue val;
+  SwfdecBits bits;
+  guint type;
+
+  swfdec_bits_init_data (&bits, data, len);
+  while (swfdec_bits_left (&bits)) {
+    memset (&val, 0, sizeof (ViviDecompilerValue));
+    type = swfdec_bits_get_u8 (&bits);
+    switch (type) {
+      case 0: /* string */
+	{
+	  char *s = swfdec_bits_get_string (&bits, dec->script->version);
+	  if (s == NULL)
+	    return FALSE;
+	  val.value = escape_string (s);
+	  g_free (s);
+	  break;
+	}
+      case 1: /* float */
+	val.value = g_strdup_printf ("%f", swfdec_bits_get_float (&bits));
+	break;
+      case 2: /* null */
+	val.value = g_strdup ("null");
+	break;
+      case 3: /* undefined */
+	val.value = g_strdup ("undefined");
+	break;
+      case 4: /* register */
+	{
+	  vivi_decompiler_value_copy (&val,
+	      vivi_decompiler_state_get_register (state, swfdec_bits_get_u8 (&bits)));
+	  break;
+	}
+      case 5: /* boolean */
+	val.value = g_strdup (swfdec_bits_get_u8 (&bits) ? "true" : "false");
+	break;
+      case 6: /* double */
+	val.value = g_strdup_printf ("%g", swfdec_bits_get_double (&bits));
+	break;
+      case 7: /* 32bit int */
+	val.value = g_strdup_printf ("%d", swfdec_bits_get_u32 (&bits));
+	break;
+      case 8: /* 8bit ConstantPool address */
+      case 9: /* 16bit ConstantPool address */
+	{
+	  guint i = type == 8 ? swfdec_bits_get_u8 (&bits) : swfdec_bits_get_u16 (&bits);
+	  if (state->pool == NULL) {
+	    g_printerr ("no constant pool to push from");
+	    return FALSE;
+	  }
+	  if (i >= swfdec_constant_pool_size (state->pool)) {
+	    g_printerr ("constant pool index %u too high - only %u elements\n",
+		i, swfdec_constant_pool_size (state->pool));
+	    return FALSE;
+	  }
+	  val.value = escape_string (swfdec_constant_pool_get (state->pool, i));
+	  break;
+	}
+      default:
+	g_printerr ("Push: type %u not implemented", type);
+	return FALSE;
+    }
+    vivi_decompiler_state_push (state, &val);
+  }
+
+  state->pc = data + len;
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_pop (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviDecompilerValue val;
+  
+  vivi_decompiler_state_pop (state, &val);
+  state->pc++;
+  vivi_decompiler_emit_line (dec, state, "%s;", val.value);
+  vivi_decompiler_value_reset (&val);
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_constant_pool (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  if (state->pool)
+    swfdec_constant_pool_free (state->pool);
+
+  state->pool = swfdec_constant_pool_new_from_action (data, len, dec->script->version);
+  state->pc = data + len;
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_trace (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviDecompilerValue val;
+  
+  vivi_decompiler_state_pop (state, &val);
+  state->pc++;
+  vivi_decompiler_emit_line (dec, state, "trace (%s);", val.value);
+  vivi_decompiler_value_reset (&val);
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_end (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  state->pc = dec->script->exit;
+  vivi_decompiler_emit_line (dec, state, "return;");
+  return TRUE;
+}
+
+static gboolean
+vivi_decompile_get_url2 (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  ViviDecompilerValue url, target;
+  const char *fun;
+
+  vivi_decompiler_state_pop (state, &url);
+  vivi_decompiler_state_pop (state, &target);
+
+  state->pc = data + len;
+  if (len != 1) {
+    vivi_decompiler_emit_error (dec, state, "invalid getURL2 command");   
+  } else {
+    guint method = data[0] & 3;
+    guint internal = data[0] & 64;
+    guint variables = data[0] & 128;
+    if (method == 3) {
+      vivi_decompiler_emit_error (dec, state, "GetURL method 3 invalid");
+      method = 0;
+    }
+
+    if (variables) {
+      fun = "loadVariables";
+    } else if (internal) {
+      fun = "loadMovie";
+    } else {
+      fun = "getURL";
+    }
+    if (method == 0)
+      vivi_decompiler_emit_line (dec, state, "%s (%s, %s);", fun, url.value, target.value);
+    else
+      vivi_decompiler_emit_line (dec, state, "%s (%s, %s, %s);", 
+	  fun, url.value, target.value, method == 1 ? "\"GET\"" : "\"POST\"");
+  }
+  vivi_decompiler_value_reset (&url);
+  vivi_decompiler_value_reset (&target);
+  return TRUE;
+}
+
+static DecompileFunc decompile_funcs[256] = {
+  [SWFDEC_AS_ACTION_END] = vivi_decompile_end,
+  [SWFDEC_AS_ACTION_TRACE] = vivi_decompile_trace,
+  [SWFDEC_AS_ACTION_POP] = vivi_decompile_pop,
+
+  [SWFDEC_AS_ACTION_PUSH] = vivi_decompile_push,
+  [SWFDEC_AS_ACTION_CONSTANT_POOL] = vivi_decompile_constant_pool,
+  [SWFDEC_AS_ACTION_GET_URL2] = vivi_decompile_get_url2,
+};
+
+static gboolean
+vivi_decompiler_process (ViviDecompiler *dec, ViviDecompilerState *state,
+    guint code, const guint8 *data, guint len)
+{
+  switch (code) {
+    default:
+      if (decompile_funcs[code]) {
+	return decompile_funcs[code] (dec, state, code, data, len);
+      } else {
+	g_printerr ("unknown bytecode %20X %u\n", code, code);
+	return FALSE;
+      }
+  };
+
+  return TRUE;
+}
+
+static void
 vivi_decompiler_run (ViviDecompiler *dec)
 {
-  ViviDecompilerState *state = vivi_decompiler_state_new (4);
+  ViviDecompilerState *state;
+  const guint8 *start, *end;
+  const guint8 *data;
+  guint code, len;
+
+  start = dec->script->buffer->data;
+  end = start + dec->script->buffer->length;
+  state = vivi_decompiler_state_new (dec->script->main, 4);
+  if (dec->script->constant_pool) {
+    state->pool = swfdec_constant_pool_new_from_action (dec->script->constant_pool->data,
+	dec->script->constant_pool->length, dec->script->version);
+  }
+
+  while (state->pc != dec->script->exit) {
+    code = state->pc[0];
+    if (code & 0x80) {
+      if (state->pc + 2 >= end) {
+	g_printerr ("bytecode %u length value out of range", code);
+	goto error;
+      }
+      data = state->pc + 3;
+      len = state->pc[1] | state->pc[2] << 8;
+      if (data + len > end) {
+	g_printerr ("bytecode %u length %u out of range", code, len);
+	goto error;
+      }
+    } else {
+      data = NULL;
+      len = 0;
+    }
+    if (!vivi_decompiler_process (dec, state, code, data, len))
+      goto error;
+    if (state->pc < start || state->pc >= end) {
+      g_printerr ("program counter out of range");
+      goto error;
+    }
+  }
 
+error:
   vivi_decompiler_state_free (state);
 }
 
@@ -144,7 +487,7 @@ vivi_decompiler_get_line (ViviDecompiler *dec, guint i)
   g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
   g_return_val_if_fail (i < dec->lines->len, NULL);
 
-  return (const char *) &g_ptr_array_index (dec->lines, i);
+  return g_ptr_array_index (dec->lines, i);
 }
 
 
commit 3993357e58aa808c691774e8e2e0195121005335
Author: Benjamin Otte <otte at gnome.org>
Date:   Sat Mar 15 00:45:20 2008 +0100

    add more code that compiles
    
    But no code works

diff --git a/vivified/compiler/.gitignore b/vivified/compiler/.gitignore
index b580c89..8761c5f 100644
--- a/vivified/compiler/.gitignore
+++ b/vivified/compiler/.gitignore
@@ -10,3 +10,5 @@ Makefile.in
 *.la
 *.lo
 *.loT
+
+vivi-decompile
diff --git a/vivified/compiler/Makefile.am b/vivified/compiler/Makefile.am
index 9c272ec..97c8001 100644
--- a/vivified/compiler/Makefile.am
+++ b/vivified/compiler/Makefile.am
@@ -11,3 +11,11 @@ noinst_HEADERS = \
 	vivified-compiler.h
 
 
+noinst_PROGRAMS = vivi-decompile
+
+vivi_decompile_SOURCES = \
+	decompiler.c
+
+vivi_decompile_CFLAGS =  $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+vivi_decompile_LDFLAGS = $(SWFDEC_LIBS)
+vivi_decompile_LDADD = libvivified-compiler.la
diff --git a/vivified/compiler/decompiler.c b/vivified/compiler/decompiler.c
new file mode 100644
index 0000000..ad0d7ac
--- /dev/null
+++ b/vivified/compiler/decompiler.c
@@ -0,0 +1,77 @@
+/* Swfdec
+ * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <swfdec/swfdec.h>
+
+#include <swfdec/swfdec_player_internal.h>
+#include <swfdec/swfdec_resource.h>
+#include <swfdec/swfdec_script_internal.h>
+#include <swfdec/swfdec_sprite_movie.h>
+#include <swfdec/swfdec_swf_decoder.h>
+
+#include "vivi_decompiler.h"
+
+static void
+decode_script (gpointer offset, gpointer scriptp, gpointer unused)
+{
+  SwfdecScript *script = scriptp;
+  ViviDecompiler *dec = vivi_decompiler_new (scriptp);
+  guint i;
+
+  g_print ("%s:\n", script->name);
+  for (i = 0; i < vivi_decompiler_get_n_lines (dec); i++) {
+    g_print ("%s  \n", vivi_decompiler_get_line (dec, i));
+  }
+}
+
+int 
+main (int argc, char *argv[])
+{
+  SwfdecPlayer *player;
+  SwfdecSwfDecoder *dec;
+  SwfdecURL *url;
+
+  if (argc < 2) {
+    g_print ("%s FILENAME\n", argv[0]);
+    return 1;
+  }
+
+  player = swfdec_player_new (NULL);
+  url = swfdec_url_new_from_input (argv[1]);
+  swfdec_player_set_url (player, url);
+  swfdec_url_free (url);
+  /* FIXME: HACK! */
+  swfdec_player_advance (player, 0);
+  if (!SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data)) {
+    g_printerr ("Error parsing file \"%s\"\n", argv[1]);
+    g_object_unref (player);
+    player = NULL;
+    return 1;
+  }
+  dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder);
+
+  g_hash_table_foreach (dec->scripts, decode_script, NULL);
+
+  g_object_unref (player);
+  return 0;
+}
+
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
index 1d71c91..b35620d 100644
--- a/vivified/compiler/vivi_decompiler.c
+++ b/vivified/compiler/vivi_decompiler.c
@@ -23,12 +23,84 @@
 
 #include "vivi_decompiler.h"
 
+/*** DECOMPILER ENGINE ***/
+
+typedef struct _ViviDecompilerValue ViviDecompilerValue;
+struct _ViviDecompilerValue {
+  char *	value;
+  gboolean	unconstant;
+};
+
+static void
+vivi_decompiler_value_reset (ViviDecompilerValue *value)
+{
+  g_free (value->value);
+  value->value = NULL;
+  value->unconstant = TRUE;
+}
+
+typedef struct _ViviDecompilerState ViviDecompilerState;
+struct _ViviDecompilerState {
+  ViviDecompilerValue *	registers;
+  guint			n_registers;
+  GArray *		stack;
+};
+
+static void
+vivi_decompiler_state_free (ViviDecompilerState *state)
+{
+  guint i;
+
+  for (i = 0; i < state->n_registers; i++) {
+    vivi_decompiler_value_reset (&state->registers[i]);
+  }
+  for (i = 0; i < state->stack->len; i++) {
+    vivi_decompiler_value_reset (&g_array_index (state->stack, ViviDecompilerValue, i));
+  }
+
+  g_array_free (state->stack, TRUE);
+  g_slice_free1 (sizeof (ViviDecompilerValue) * state->n_registers, state->registers);
+  g_slice_free (ViviDecompilerState, state);
+}
+
+static ViviDecompilerState *
+vivi_decompiler_state_new (guint n_registers)
+{
+  ViviDecompilerState *state = g_slice_new0 (ViviDecompilerState);
+
+  state->registers = g_slice_alloc0 (sizeof (ViviDecompilerValue) * n_registers);
+  state->n_registers = n_registers;
+  state->stack = g_array_new (FALSE, TRUE, sizeof (ViviDecompilerValue));
+
+  return state;
+}
+
+static void
+vivi_decompiler_run (ViviDecompiler *dec)
+{
+  ViviDecompilerState *state = vivi_decompiler_state_new (4);
+
+  vivi_decompiler_state_free (state);
+}
+
+/*** OBJECT ***/
+
 G_DEFINE_TYPE (ViviDecompiler, vivi_decompiler, G_TYPE_OBJECT)
 
 static void
 vivi_decompiler_dispose (GObject *object)
 {
-  //ViviDecompiler *decompiler = VIVI_DECOMPILER (object);
+  ViviDecompiler *dec = VIVI_DECOMPILER (object);
+  guint i;
+
+  if (dec->script) {
+    swfdec_script_unref (dec->script);
+    dec->script = NULL;
+  }
+  for (i = 0; i < dec->lines->len; i++) {
+    g_free (&g_ptr_array_index (dec->lines, i));
+  }
+  g_ptr_array_free (dec->lines, TRUE);
 
   G_OBJECT_CLASS (vivi_decompiler_parent_class)->dispose (object);
 }
@@ -42,7 +114,37 @@ vivi_decompiler_class_init (ViviDecompilerClass *klass)
 }
 
 static void
-vivi_decompiler_init (ViviDecompiler *decompiler)
+vivi_decompiler_init (ViviDecompiler *dec)
 {
+  dec->lines = g_ptr_array_new ();
+}
+
+ViviDecompiler *
+vivi_decompiler_new (SwfdecScript *script)
+{
+  ViviDecompiler *dec = g_object_new (VIVI_TYPE_DECOMPILER, NULL);
+
+  dec->script = swfdec_script_ref (script);
+  vivi_decompiler_run (dec);
+
+  return dec;
 }
 
+guint
+vivi_decompiler_get_n_lines (ViviDecompiler *dec)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), 0);
+
+  return dec->lines->len;
+}
+
+const char *
+vivi_decompiler_get_line (ViviDecompiler *dec, guint i)
+{
+  g_return_val_if_fail (VIVI_IS_DECOMPILER (dec), NULL);
+  g_return_val_if_fail (i < dec->lines->len, NULL);
+
+  return (const char *) &g_ptr_array_index (dec->lines, i);
+}
+
+
diff --git a/vivified/compiler/vivi_decompiler.h b/vivified/compiler/vivi_decompiler.h
index b75a2fa..0ba52f3 100644
--- a/vivified/compiler/vivi_decompiler.h
+++ b/vivified/compiler/vivi_decompiler.h
@@ -38,6 +38,9 @@ typedef struct _ViviDecompilerClass ViviDecompilerClass;
 struct _ViviDecompiler
 {
   SwfdecAsObject	object;
+
+  SwfdecScript *	script;
+  GPtrArray *		lines;
 };
 
 struct _ViviDecompilerClass
@@ -47,8 +50,10 @@ struct _ViviDecompilerClass
 
 GType			vivi_decompiler_get_type   	(void);
 
-void			vivi_decompiler_set_active	(ViviDecompiler *	decompiler,
-							 gboolean		active);
+ViviDecompiler *	vivi_decompiler_new		(SwfdecScript *		script);
+guint			vivi_decompiler_get_n_lines	(ViviDecompiler *	dec);
+const char *		vivi_decompiler_get_line	(ViviDecompiler *	dec,
+							 guint			i);
 
 G_END_DECLS
 #endif
commit 82d7c4d0829152e02a85f0099607c9a6a904ed85
Author: Benjamin Otte <otte at gnome.org>
Date:   Fri Mar 14 22:53:40 2008 +0100

    add initial infrastructure for (de)compiler lib

diff --git a/configure.ac b/configure.ac
index d095054..721cf8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -338,6 +338,7 @@ test/trace/Makefile
 test/various/Makefile
 tools/Makefile
 vivified/Makefile
+vivified/compiler/Makefile
 vivified/core/Makefile
 vivified/dock/Makefile
 vivified/ui/Makefile
diff --git a/vivified/Makefile.am b/vivified/Makefile.am
index 8289102..d231bea 100644
--- a/vivified/Makefile.am
+++ b/vivified/Makefile.am
@@ -1 +1 @@
-SUBDIRS = core dock ui
+SUBDIRS = compiler core dock ui
diff --git a/vivified/compiler/.gitignore b/vivified/compiler/.gitignore
new file mode 100644
index 0000000..b580c89
--- /dev/null
+++ b/vivified/compiler/.gitignore
@@ -0,0 +1,12 @@
+*~
+CVS
+.cvsignore
+.deps
+.libs
+
+Makefile
+Makefile.in
+*.o
+*.la
+*.lo
+*.loT
diff --git a/vivified/compiler/Makefile.am b/vivified/compiler/Makefile.am
new file mode 100644
index 0000000..9c272ec
--- /dev/null
+++ b/vivified/compiler/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libvivified-compiler.la
+
+libvivified_compiler_la_CFLAGS = $(GLOBAL_CFLAGS) $(SWFDEC_CFLAGS)
+libvivified_compiler_la_LDFLAGS = $(SWFDEC_LIBS)
+
+libvivified_compiler_la_SOURCES = \
+	vivi_decompiler.c
+
+noinst_HEADERS = \
+	vivi_decompiler.h \
+	vivified-compiler.h
+
+
diff --git a/vivified/compiler/vivi_decompiler.c b/vivified/compiler/vivi_decompiler.c
new file mode 100644
index 0000000..1d71c91
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler.c
@@ -0,0 +1,48 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "vivi_decompiler.h"
+
+G_DEFINE_TYPE (ViviDecompiler, vivi_decompiler, G_TYPE_OBJECT)
+
+static void
+vivi_decompiler_dispose (GObject *object)
+{
+  //ViviDecompiler *decompiler = VIVI_DECOMPILER (object);
+
+  G_OBJECT_CLASS (vivi_decompiler_parent_class)->dispose (object);
+}
+
+static void
+vivi_decompiler_class_init (ViviDecompilerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = vivi_decompiler_dispose;
+}
+
+static void
+vivi_decompiler_init (ViviDecompiler *decompiler)
+{
+}
+
diff --git a/vivified/compiler/vivi_decompiler.h b/vivified/compiler/vivi_decompiler.h
new file mode 100644
index 0000000..b75a2fa
--- /dev/null
+++ b/vivified/compiler/vivi_decompiler.h
@@ -0,0 +1,54 @@
+/* Vivified
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef _VIVI_DECOMPILER_H_
+#define _VIVI_DECOMPILER_H_
+
+#include <swfdec/swfdec.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _ViviDecompiler ViviDecompiler;
+typedef struct _ViviDecompilerClass ViviDecompilerClass;
+
+#define VIVI_TYPE_DECOMPILER                    (vivi_decompiler_get_type())
+#define VIVI_IS_DECOMPILER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIVI_TYPE_DECOMPILER))
+#define VIVI_IS_DECOMPILER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), VIVI_TYPE_DECOMPILER))
+#define VIVI_DECOMPILER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIVI_TYPE_DECOMPILER, ViviDecompiler))
+#define VIVI_DECOMPILER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
+#define VIVI_DECOMPILER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), VIVI_TYPE_DECOMPILER, ViviDecompilerClass))
+
+struct _ViviDecompiler
+{
+  SwfdecAsObject	object;
+};
+
+struct _ViviDecompilerClass
+{
+  SwfdecAsObjectClass	object_class;
+};
+
+GType			vivi_decompiler_get_type   	(void);
+
+void			vivi_decompiler_set_active	(ViviDecompiler *	decompiler,
+							 gboolean		active);
+
+G_END_DECLS
+#endif
diff --git a/vivified/compiler/vivified-compiler.h b/vivified/compiler/vivified-compiler.h
new file mode 100644
index 0000000..81b0539
--- /dev/null
+++ b/vivified/compiler/vivified-compiler.h
@@ -0,0 +1,25 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __VIVIFIED_COMPILER_H__
+#define __VIVIFIED_COMPILER_H__
+
+#include <vivified/compiler/vivi_compiler.h>
+
+#endif


More information about the Swfdec-commits mailing list