[Swfdec] Branch 'as' - 4 commits - libswfdec/Makefile.am
libswfdec/swfdec_as_context.c libswfdec/swfdec_as_frame.c
libswfdec/swfdec_as_interpret.c
libswfdec/swfdec_as_interpret.h libswfdec/swfdec_as_object.c
libswfdec/swfdec_as_types.c libswfdec/swfdec_as_types.h
libswfdec/swfdec_script.c libswfdec/swfdec_script.h
Benjamin Otte
company at kemper.freedesktop.org
Wed Apr 4 05:51:36 PDT 2007
libswfdec/Makefile.am | 2
libswfdec/swfdec_as_context.c | 30
libswfdec/swfdec_as_frame.c | 4
libswfdec/swfdec_as_interpret.c | 2472 +++++++++++++++++++++++++++++++++++
libswfdec/swfdec_as_interpret.h | 45
libswfdec/swfdec_as_object.c | 5
libswfdec/swfdec_as_types.c | 43
libswfdec/swfdec_as_types.h | 5
libswfdec/swfdec_script.c | 2789 ----------------------------------------
libswfdec/swfdec_script.h | 4
10 files changed, 2592 insertions(+), 2807 deletions(-)
New commits:
diff-tree 121a4494b3f5c785daac627b908593585b591182 (from ee1c84df7a50b023262001feb21c90380798161a)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Apr 4 14:48:41 2007 +0200
put interpreting in its own file and implement the first few functions
The ultra-important first ever working ActionScript movie works again
diff --git a/libswfdec/Makefile.am b/libswfdec/Makefile.am
index b46bcc0..51ebd32 100644
--- a/libswfdec/Makefile.am
+++ b/libswfdec/Makefile.am
@@ -28,6 +28,7 @@ libswfdec_ at SWFDEC_MAJORMINOR@_la_SOURCES
swfdec_as_context.c \
swfdec_as_frame.c \
swfdec_as_function.c \
+ swfdec_as_interpret.c \
swfdec_as_object.c \
swfdec_as_stack.c \
swfdec_as_types.c \
@@ -114,6 +115,7 @@ noinst_HEADERS = \
swfdec_as_context.h \
swfdec_as_frame.h \
swfdec_as_function.h \
+ swfdec_as_interpret.h \
swfdec_as_object.h \
swfdec_as_stack.h \
swfdec_as_types.h \
diff --git a/libswfdec/swfdec_as_context.c b/libswfdec/swfdec_as_context.c
index 8fe289a..8d31c73 100644
--- a/libswfdec/swfdec_as_context.c
+++ b/libswfdec/swfdec_as_context.c
@@ -24,6 +24,7 @@
#include <string.h>
#include "swfdec_as_context.h"
#include "swfdec_as_frame.h"
+#include "swfdec_as_interpret.h"
#include "swfdec_as_object.h"
#include "swfdec_as_stack.h"
#include "swfdec_as_types.h"
@@ -327,22 +328,6 @@ swfdec_as_context_new (void)
return g_object_new (SWFDEC_TYPE_AS_CONTEXT, NULL);
}
-/* defines minimum and maximum versions for which we have seperate scripts */
-#define MINSCRIPTVERSION 3
-#define MAXSCRIPTVERSION 7
-#define EXTRACT_VERSION(v) MIN ((v) - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION)
-
-typedef void (* SwfdecActionExec) (SwfdecAsContext *cx, guint action, const guint8 *data, guint len);
-typedef struct {
- const char * name; /* name identifying the action */
- char * (* print) (guint action, const guint8 *data, guint len);
- int remove; /* values removed from stack or -1 for dynamic */
- int add; /* values added to the stack or -1 for dynamic */
- SwfdecActionExec exec[MAXSCRIPTVERSION - MINSCRIPTVERSION + 1];
- /* array is for version 3, 4, 5, 6, 7+ */
-} SwfdecActionSpec;
-
-extern const SwfdecActionSpec actions[256];
void
swfdec_as_context_run (SwfdecAsContext *context)
{
@@ -367,9 +352,11 @@ start:
return;
script = frame->script;
stack = frame->stack;
- version = EXTRACT_VERSION (script->version);
+ version = SWFDEC_AS_EXTRACT_SCRIPT_VERSION (script->version);
+ context->version = script->version;
startpc = script->buffer->data;
endpc = startpc + script->buffer->length;
+ pc = frame->pc;
while (TRUE) {
if (pc == endpc) {
@@ -383,7 +370,7 @@ start:
/* decode next action */
action = *pc;
- spec = actions + action;
+ spec = swfdec_as_actions + action;
if (action == 0)
break;
if (action & 0x80) {
@@ -405,8 +392,9 @@ start:
}
/* check action is valid */
if (spec->exec[version] == NULL) {
- SWFDEC_ERROR ("cannot interpret action %u %s for version %u", action,
- spec->name ? spec->name : "Unknown", script->version);
+ SWFDEC_ERROR ("cannot interpret action %3u 0x%02X %s for version %u", action,
+ action, spec->name ? spec->name : "Unknown", script->version);
+ /* FIXME: figure out what flash player does here */
goto error;
}
if (spec->remove > 0) {
@@ -422,7 +410,7 @@ start:
#ifndef G_DISABLE_ASSERT
check = (spec->add >= 0 && spec->remove >= 0) ? stack->cur + spec->add - spec->remove : NULL;
#endif
- spec->exec[version] (NULL, action, data, len);
+ spec->exec[version] (context, action, data, len);
if (frame == context->frame) {
#ifndef G_DISABLE_ASSERT
if (check != NULL && check != stack->cur) {
diff --git a/libswfdec/swfdec_as_interpret.c b/libswfdec/swfdec_as_interpret.c
new file mode 100644
index 0000000..6570e65
--- /dev/null
+++ b/libswfdec/swfdec_as_interpret.c
@@ -0,0 +1,2472 @@
+/* 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_as_interpret.h"
+#include "swfdec_as_context.h"
+#include "swfdec_as_frame.h"
+#include "swfdec_debug.h"
+
+#include <errno.h>
+#include <math.h>
+#include <string.h>
+#include "swfdec_decoder.h"
+#include "swfdec_movie.h"
+#include "swfdec_player_internal.h"
+#include "swfdec_root_movie.h"
+#include "swfdec_sprite.h"
+#include "swfdec_sprite_movie.h"
+
+/* Define this to get SWFDEC_WARN'd about missing properties of objects.
+ * This can be useful to find out about unimplemented native properties,
+ * but usually just causes a lot of spam. */
+//#define SWFDEC_WARN_MISSING_PROPERTIES
+
+/*** SUPPORT FUNCTIONS ***/
+
+#define swfdec_action_has_register(cx, i) \
+ ((i) < ((SwfdecScript *) (cx)->fp->swf)->n_registers)
+
+static SwfdecMovie *
+swfdec_action_get_target (SwfdecAsContext *context)
+{
+ SwfdecAsObject *object = context->frame->scope;
+
+ if (!SWFDEC_IS_MOVIE (object)) {
+ SWFDEC_ERROR ("no valid target");
+ return NULL;
+ }
+ return SWFDEC_MOVIE (object);
+}
+
+#if 0
+static void
+swfdec_action_push_string (SwfdecAsContext *cx, const char *s)
+{
+ JSString *string = JS_NewStringCopyZ (cx, s);
+ if (string == NULL)
+ return JS_FALSE;
+ *cx->fp->sp++ = STRING_TO_JSVAL (string);
+ return JS_TRUE;
+}
+
+static void
+swfdec_value_to_boolean_5 (SwfdecAsContext *cx, jsval val)
+{
+ if (JSVAL_IS_BOOLEAN (val)) {
+ return JSVAL_TO_BOOLEAN (val);
+ } else if (JSVAL_IS_INT (val)) {
+ return JSVAL_TO_INT (val) != 0;
+ } else if (JSVAL_IS_DOUBLE (val)) {
+ double d = *JSVAL_TO_DOUBLE (val);
+ return d != 0.0 && !isnan (d);
+ } else if (JSVAL_IS_STRING (val)) {
+ double d;
+ if (!JS_ValueToNumber (cx, val, &d))
+ return 0;
+ return d != 0.0 && !isnan (d);
+ } else if (JSVAL_IS_NULL (val)) {
+ return JS_FALSE;
+ } else if (JSVAL_IS_VOID (val)) {
+ return JS_FALSE;
+ } else if (JSVAL_IS_OBJECT (val)) {
+ return JS_TRUE;
+ }
+ g_assert_not_reached ();
+ return JS_FALSE;
+}
+
+static void
+swfdec_value_to_boolean_7 (SwfdecAsContext *cx, jsval val)
+{
+ if (JSVAL_IS_BOOLEAN (val)) {
+ return JSVAL_TO_BOOLEAN (val);
+ } else if (JSVAL_IS_INT (val)) {
+ return JSVAL_TO_INT (val) != 0;
+ } else if (JSVAL_IS_DOUBLE (val)) {
+ double d = *JSVAL_TO_DOUBLE (val);
+ return d != 0.0 && !isnan (d);
+ } else if (JSVAL_IS_STRING (val)) {
+ return JS_GetStringLength (JSVAL_TO_STRING (val)) > 0;
+ } else if (JSVAL_IS_NULL (val)) {
+ return JS_FALSE;
+ } else if (JSVAL_IS_VOID (val)) {
+ return JS_FALSE;
+ } else if (JSVAL_IS_OBJECT (val)) {
+ return JS_TRUE;
+ }
+ g_assert_not_reached ();
+ return JS_FALSE;
+}
+
+static double
+swfdec_value_to_number (SwfdecAsContext *cx, jsval val)
+{
+ if (JSVAL_IS_INT (val)) {
+ return JSVAL_TO_INT (val);
+ } else if (JSVAL_IS_DOUBLE (val)) {
+ return *JSVAL_TO_DOUBLE (val);
+ } else if (JSVAL_IS_BOOLEAN (val)) {
+ return JSVAL_TO_BOOLEAN (val);
+ } else if (JSVAL_IS_STRING (val)) {
+ double d;
+ if (!JS_ValueToNumber (cx, val, &d))
+ return 0;
+ return d;
+ } else if (JSVAL_IS_OBJECT(val) && (((SwfdecScript *) cx->fp->swf)->version >= 6)) {
+ /* Checking for version 6 is completely wrong, but a lot of the testsuite
+ * depends on it (oops).
+ * The code calls the valueOf function and returns 0 if no such function exists.
+ */
+ return JSVAL_IS_NULL (val) ? 0 : *cx->runtime->jsNaN;
+ } else {
+ return 0;
+ }
+}
+
+static void
+swfdec_value_to_number_7 (SwfdecAsContext *cx, jsval val, double *d)
+{
+ if (JSVAL_IS_OBJECT (val)) {
+ *d = *cx->runtime->jsNaN;
+ return JS_TRUE;
+ } else if (JSVAL_IS_STRING (val) &&
+ JS_GetStringLength (JSVAL_TO_STRING (val)) == 0) {
+ *d = *cx->runtime->jsNaN;
+ return JS_TRUE;
+ } else {
+ return JS_ValueToNumber (cx, val, d);
+ }
+}
+#endif
+
+/*** ALL THE ACTION IS HERE ***/
+
+static void
+swfdec_action_stop (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_action_get_target (cx);
+ if (movie)
+ movie->stopped = TRUE;
+ else
+ SWFDEC_ERROR ("no movie to stop");
+}
+
+static void
+swfdec_action_play (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_action_get_target (cx);
+ if (movie)
+ movie->stopped = FALSE;
+ else
+ SWFDEC_ERROR ("no movie to play");
+}
+
+static void
+swfdec_action_next_frame (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_action_get_target (cx);
+ if (movie) {
+ if (movie->frame + 1 < movie->n_frames) {
+ swfdec_movie_goto (movie, movie->frame + 1);
+ } else {
+ SWFDEC_INFO ("can't execute nextFrame, already at last frame");
+ }
+ } else {
+ SWFDEC_ERROR ("no movie to nextFrame on");
+ }
+}
+
+static void
+swfdec_action_previous_frame (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_action_get_target (cx);
+ if (movie) {
+ if (movie->frame > 0) {
+ swfdec_movie_goto (movie, movie->frame - 1);
+ } else {
+ SWFDEC_INFO ("can't execute previousFrame, already at first frame");
+ }
+ } else {
+ SWFDEC_ERROR ("no movie to previousFrame on");
+ }
+}
+
+static void
+swfdec_action_goto_frame (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_action_get_target (cx);
+ guint frame;
+
+ if (len != 2) {
+ SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len);
+ return;
+ }
+ frame = GUINT16_FROM_LE (*((guint16 *) data));
+ if (movie) {
+ swfdec_movie_goto (movie, frame);
+ movie->stopped = TRUE;
+ } else {
+ SWFDEC_ERROR ("no movie to goto on");
+ }
+}
+
+static void
+swfdec_action_goto_label (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_action_get_target (cx);
+
+ if (!memchr (data, 0, len)) {
+ SWFDEC_ERROR ("GotoLabel action does not specify a string");
+ return;
+ }
+
+ if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
+ int frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, (const char *) data);
+ if (frame == -1)
+ return;
+ swfdec_movie_goto (movie, frame);
+ movie->stopped = TRUE;
+ } else {
+ SWFDEC_ERROR ("no movie to goto on");
+ }
+}
+
+#if 0
+static int
+swfdec_value_to_frame (SwfdecAsContext *cx, SwfdecMovie *movie, jsval val)
+{
+ int frame;
+
+ if (JSVAL_IS_STRING (val)) {
+ const char *name = swfdec_js_to_string (cx, val);
+ char *end;
+ if (name == NULL ||
+ !SWFDEC_IS_SPRITE_MOVIE (movie))
+ return -1;
+ if (strchr (name, ':')) {
+ SWFDEC_ERROR ("FIXME: handle targets");
+ }
+ /* treat valid encoded numbers as numbers, otherwise assume it's a frame label */
+ frame = strtol (name, &end, 0);
+ if (*end != '\0')
+ frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name);
+ else
+ frame--;
+ } else if (JSVAL_IS_INT (val)) {
+ return JSVAL_TO_INT (val) - 1;
+ } else if (JSVAL_IS_DOUBLE (val)) {
+ return (int) *JSVAL_TO_DOUBLE (val) - 1;
+ } else {
+ /* FIXME: how do we treat undefined etc? */
+ frame = -1;
+ }
+ return frame;
+}
+
+static void
+swfdec_action_goto_frame2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecBits bits;
+ guint bias;
+ gboolean play;
+ jsval val;
+ SwfdecMovie *movie;
+
+ swfdec_bits_init_data (&bits, data, len);
+ if (swfdec_bits_getbits (&bits, 6)) {
+ SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
+ }
+ bias = swfdec_bits_getbit (&bits);
+ play = swfdec_bits_getbit (&bits);
+ if (bias) {
+ bias = swfdec_bits_get_u16 (&bits);
+ }
+ val = cx->fp->sp[-1];
+ cx->fp->sp--;
+ movie = swfdec_action_get_target (cx);
+ /* now set it */
+ if (movie) {
+ int frame = swfdec_value_to_frame (cx, movie, val);
+ if (frame < 0)
+ return JS_TRUE;
+ frame += bias;
+ frame = CLAMP (frame, 0, (int) movie->n_frames - 1);
+ swfdec_movie_goto (movie, frame);
+ movie->stopped = !play;
+ } else {
+ SWFDEC_ERROR ("no movie to GotoFrame2 on");
+ }
+ return JS_TRUE;
+}
+#endif
+
+static void
+swfdec_script_skip_actions (SwfdecAsContext *cx, guint jump)
+{
+ SwfdecScript *script = cx->frame->script;
+ guint8 *pc = cx->frame->pc;
+ guint8 *endpc = script->buffer->data + script->buffer->length;
+
+ /* jump instructions */
+ do {
+ if (pc >= endpc)
+ break;
+ if (*pc & 0x80) {
+ if (pc + 2 >= endpc)
+ break;
+ pc += 3 + GUINT16_FROM_LE (*((guint16 *) (pc + 1)));
+ } else {
+ pc++;
+ }
+ } while (jump-- > 0);
+ cx->frame->pc = pc;
+}
+
+#if 0
+static void
+swfdec_action_wait_for_frame2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval val;
+ SwfdecMovie *movie;
+
+ if (len != 1) {
+ SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
+ return JS_FALSE;
+ }
+ val = cx->fp->sp[-1];
+ cx->fp->sp--;
+ movie = swfdec_action_get_target (cx);
+ if (movie) {
+ int frame = swfdec_value_to_frame (cx, movie, val);
+ guint jump = data[2];
+ guint loaded;
+ if (frame < 0)
+ return JS_TRUE;
+ if (SWFDEC_IS_ROOT_MOVIE (movie)) {
+ SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie)->decoder;
+ loaded = dec->frames_loaded;
+ g_assert (loaded <= movie->n_frames);
+ } else {
+ loaded = movie->n_frames;
+ }
+ if (loaded < (guint) frame)
+ swfdec_script_skip_actions (cx, jump);
+ } else {
+ SWFDEC_ERROR ("no movie to WaitForFrame2 on");
+ }
+ return JS_TRUE;
+}
+#endif
+
+static void
+swfdec_action_wait_for_frame (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie;
+ guint frame, jump, loaded;
+
+ if (len != 3) {
+ SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len);
+ return;
+ }
+ movie = swfdec_action_get_target (cx);
+ if (movie == NULL) {
+ SWFDEC_ERROR ("no movie for WaitForFrame");
+ return;
+ }
+
+ frame = GUINT16_FROM_LE (*((guint16 *) data));
+ jump = data[2];
+ if (SWFDEC_IS_ROOT_MOVIE (movie)) {
+ SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie)->decoder;
+ loaded = dec->frames_loaded;
+ g_assert (loaded <= movie->n_frames);
+ } else {
+ loaded = movie->n_frames;
+ }
+ if (loaded < frame)
+ swfdec_script_skip_actions (cx, jump);
+}
+
+#if 0
+static void
+swfdec_action_constant_pool (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecConstantPool *pool;
+
+ pool = swfdec_constant_pool_new_from_action (data, len);
+ if (pool == NULL)
+ return JS_FALSE;
+ if (cx->fp->constant_pool)
+ swfdec_constant_pool_free (cx->fp->constant_pool);
+ cx->fp->constant_pool = pool;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_push (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ /* FIXME: supply API for this */
+ SwfdecBits bits;
+ guint stackspace = cx->fp->spend - cx->fp->sp;
+
+ swfdec_bits_init_data (&bits, data, len);
+ while (swfdec_bits_left (&bits) && stackspace-- > 0) {
+ guint type = swfdec_bits_get_u8 (&bits);
+ SWFDEC_LOG ("push type %u", type);
+ switch (type) {
+ case 0: /* string */
+ {
+ const char *s = swfdec_bits_skip_string (&bits);
+ if (!swfdec_action_push_string (cx, s))
+ return JS_FALSE;
+ break;
+ }
+ case 1: /* float */
+ {
+ double d = swfdec_bits_get_float (&bits);
+ if (!JS_NewDoubleValue (cx, d, cx->fp->sp))
+ return JS_FALSE;
+ cx->fp->sp++;
+ break;
+ }
+ case 2: /* null */
+ *cx->fp->sp++ = JSVAL_NULL;
+ break;
+ case 3: /* undefined */
+ *cx->fp->sp++ = JSVAL_VOID;
+ break;
+ case 4: /* register */
+ {
+ guint regnum = swfdec_bits_get_u8 (&bits);
+ if (!swfdec_action_has_register (cx, regnum)) {
+ SWFDEC_ERROR ("cannot Push register %u: not enough registers", regnum);
+ return JS_FALSE;
+ }
+ *cx->fp->sp++ = cx->fp->vars[regnum];
+ break;
+ }
+ case 5: /* boolean */
+ *cx->fp->sp++ = swfdec_bits_get_u8 (&bits) ? JSVAL_TRUE : JSVAL_FALSE;
+ break;
+ case 6: /* double */
+ {
+ double d = swfdec_bits_get_double (&bits);
+ if (!JS_NewDoubleValue (cx, d, cx->fp->sp))
+ return JS_FALSE;
+ cx->fp->sp++;
+ break;
+ }
+ case 7: /* 32bit int */
+ {
+ int i = swfdec_bits_get_u32 (&bits);
+ *cx->fp->sp++ = INT_TO_JSVAL (i);
+ break;
+ }
+ case 8: /* 8bit ConstantPool address */
+ {
+ guint i = swfdec_bits_get_u8 (&bits);
+ SwfdecConstantPool *pool = cx->fp->constant_pool;
+ if (pool == NULL) {
+ SWFDEC_ERROR ("no constant pool to push from");
+ return JS_FALSE;
+ }
+ if (i >= swfdec_constant_pool_size (pool)) {
+ SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
+ i, swfdec_constant_pool_size (pool));
+ return JS_FALSE;
+ }
+ if (!swfdec_action_push_string (cx, swfdec_constant_pool_get (pool, i)))
+ return JS_FALSE;
+ break;
+ }
+ case 9: /* 16bit ConstantPool address */
+ {
+ guint i = swfdec_bits_get_u16 (&bits);
+ SwfdecConstantPool *pool = cx->fp->constant_pool;
+ if (pool == NULL) {
+ SWFDEC_ERROR ("no constant pool to push from");
+ return JS_FALSE;
+ }
+ if (i >= swfdec_constant_pool_size (pool)) {
+ SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
+ i, swfdec_constant_pool_size (pool));
+ return JS_FALSE;
+ }
+ if (!swfdec_action_push_string (cx, swfdec_constant_pool_get (pool, i)))
+ return JS_FALSE;
+ break;
+ }
+ default:
+ SWFDEC_ERROR ("Push: type %u not implemented", type);
+ return JS_FALSE;
+ }
+ }
+ return swfdec_bits_left (&bits) ? JS_FALSE : JS_TRUE;
+}
+
+static void
+swfdec_action_get_variable (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *s;
+
+ s = swfdec_js_to_string (cx, cx->fp->sp[-1]);
+ if (s == NULL)
+ return JS_FALSE;
+ cx->fp->sp[-1] = swfdec_js_eval (cx, NULL, s);
+#ifdef SWFDEC_WARN_MISSING_PROPERTIES
+ if (cx->fp->sp[-1] == JSVAL_VOID) {
+ SWFDEC_WARNING ("no variable named %s", s);
+ }
+#endif
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_set_variable (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *s;
+
+ s = swfdec_js_to_string (cx, cx->fp->sp[-2]);
+ if (s == NULL)
+ return JS_FALSE;
+
+ swfdec_js_eval_set (cx, NULL, s, cx->fp->sp[-1]);
+ cx->fp->sp -= 2;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_trace (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecPlayer *player = JS_GetContextPrivate (cx);
+ const char *bytes;
+
+ bytes = swfdec_js_to_string (cx, cx->fp->sp[-1]);
+ cx->fp->sp--;
+ if (bytes == NULL)
+ return JS_TRUE;
+
+ swfdec_player_trace (player, bytes);
+ return JS_TRUE;
+}
+
+/**
+ * swfdec_action_invoke:
+ * @cx: the #SwfdecAsContext
+ * @n_args: number of arguments
+ *
+ * This function is similar to js_Invoke, however it uses a reversed stack
+ * order. sp[-1] has to be the function to call, sp[-2] will be the object the
+ * function is called on, sp[-3] is the first argument, followed by the rest of
+ * the arguments. The function removes all of these argumends from the stack
+ * and pushes the return value on top.
+ *
+ * Returns: JS_TRUE on success, JS_FALSE on failure.
+ **/
+static void
+swfdec_action_call (SwfdecAsContext *cx, guint n_args, guint flags)
+{
+ JSStackFrame *fp = cx->fp;
+ int i, j;
+ jsval tmp;
+ guint stacksize;
+
+ stacksize = fp->sp - fp->spbase;
+ g_assert (stacksize >= 2);
+ if (n_args + 2 > stacksize) {
+ SWFDEC_WARNING ("broken script. Want %u arguments, only got %u", n_args, stacksize - 2);
+ n_args = stacksize - 2;
+ if (!swfdec_script_ensure_stack (cx, n_args + 2))
+ return JS_FALSE;
+ }
+
+ j = -1;
+ i = - (n_args + 2);
+ while (i < j) {
+ tmp = fp->sp[j];
+ fp->sp[j] = fp->sp[i];
+ fp->sp[i] = tmp;
+ j--;
+ i++;
+ }
+ return js_Invoke (cx, n_args, flags);
+}
+
+/* FIXME: lots of overlap with swfdec_action_call_method */
+static void
+swfdec_action_call_function (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ const char *s;
+ guint32 n_args;
+ JSObject *obj, *pobj;
+ JSProperty *prop;
+ jsval fun;
+ JSAtom *atom;
+
+ if (!swfdec_script_ensure_stack (cx, 2))
+ return JS_FALSE;
+ s = swfdec_js_to_string (cx, fp->sp[-1]);
+ if (s == NULL)
+ return JS_FALSE;
+ if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args))
+ return JS_FALSE;
+
+ if (!(atom = js_Atomize (cx, s, strlen (s), 0)) ||
+ !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop))
+ return JS_FALSE;
+ if (!JS_GetProperty (cx, obj, s, &fun))
+ return JS_FALSE;
+ if (!JSVAL_IS_OBJECT (fun)) {
+ /* FIXME: figure out what class we operate on */
+ SWFDEC_WARNING ("%s is not a function", s);
+ }
+ fp->sp[-1] = fun;
+ fp->sp[-2] = OBJECT_TO_JSVAL (obj);
+ swfdec_action_call (cx, n_args, 0);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_call_method (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ const char *s;
+ guint32 n_args;
+ JSObject *obj;
+ jsval fun;
+
+ if (!swfdec_script_ensure_stack (cx, 3))
+ return JS_FALSE;
+ if (fp->sp[-1] == JSVAL_VOID) {
+ s = "";
+ } else {
+ s = swfdec_js_to_string (cx, fp->sp[-1]);
+ if (s == NULL)
+ return JS_FALSE;
+ }
+ if (!JS_ValueToECMAUint32 (cx, fp->sp[-3], &n_args))
+ return JS_FALSE;
+
+ if (!JS_ValueToObject (cx, fp->sp[-2], &obj))
+ return JS_FALSE;
+ if (obj == NULL)
+ goto fail;
+ if (s[0] == '\0') {
+ fun = OBJECT_TO_JSVAL (obj);
+ } else {
+ if (!JS_GetProperty (cx, obj, s, &fun))
+ return JS_FALSE;
+ if (!JSVAL_IS_OBJECT (fun)) {
+ SWFDEC_WARNING ("%s:%s is not a function", JS_GetClass (obj)->name, s);
+ }
+ }
+ fp->sp--;
+ fp->sp[-1] = fun;
+ fp->sp[-2] = OBJECT_TO_JSVAL (obj);
+ swfdec_action_call (cx, n_args, 0);
+ return JS_TRUE;
+
+fail:
+ fp->sp -= 2 + n_args;
+ fp->sp[-1] = JSVAL_VOID;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_pop (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ cx->fp->sp--;
+ return JS_TRUE;
+}
+
+static const char *
+swfdec_eval_jsval (SwfdecAsContext *cx, JSObject *obj, jsval *val)
+{
+ if (JSVAL_IS_STRING (*val)) {
+ const char *bytes = swfdec_js_to_string (cx, *val);
+ if (bytes == NULL)
+ return NULL;
+ *val = swfdec_js_eval (cx, obj, bytes);
+ return bytes;
+ } else {
+ if (obj == NULL) {
+ obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain);
+ }
+ *val = OBJECT_TO_JSVAL (obj);
+ return ".";
+ }
+}
+
+static const char *properties[22] = {
+ "_x", "_y", "_xscale", "_yscale", "_currentframe",
+ "_totalframes", "_alpha", "_visible", "_width", "_height",
+ "_rotation", "_target", "_framesloaded", "_name", "_droptarget",
+ "_url", "_highquality", "_focusrect", "_soundbuftime", "_quality",
+ "_xmouse", "_ymouse"
+};
+
+static void
+swfdec_action_get_property (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval val;
+ SwfdecMovie *movie;
+ JSObject *jsobj;
+ guint32 id;
+ const char *bytes;
+
+ if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &id))
+ return JS_FALSE;
+ val = cx->fp->sp[-2];
+ bytes = swfdec_eval_jsval (cx, NULL, &val);
+ if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) {
+ SWFDEC_WARNING ("trying to SetProperty %u, not allowed", id);
+ goto out;
+ }
+
+ if (bytes == NULL)
+ return JS_FALSE;
+ if (*bytes == '\0') {
+ JSObject *pobj;
+ JSProperty *prop;
+ JSAtom *atom = js_Atomize (cx, properties[id], strlen (properties[id]), 0);
+ if (atom == NULL)
+ return JS_FALSE;
+ if (!js_FindProperty (cx, (jsid) atom, &jsobj, &pobj, &prop))
+ return JS_FALSE;
+ if (!prop)
+ return JS_FALSE;
+ if (!OBJ_GET_PROPERTY (cx, jsobj, (jsid) prop->id, &val))
+ return JS_FALSE;
+ } else {
+ movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE);
+ if (movie == NULL) {
+ SWFDEC_WARNING ("specified target does not reference a movie clip");
+ goto out;
+ }
+
+ jsobj = JSVAL_TO_OBJECT (val);
+ val = JSVAL_VOID;
+
+ if (!JS_GetProperty (cx, jsobj, properties[id], &val))
+ return JS_FALSE;
+ }
+
+out:
+ cx->fp->sp -= 1;
+ cx->fp->sp[-1] = val;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_set_property (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval val;
+ SwfdecMovie *movie;
+ JSObject *jsobj;
+ guint32 id;
+ const char *bytes;
+
+ val = cx->fp->sp[-3];
+ if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &id))
+ return JS_FALSE;
+ bytes = swfdec_eval_jsval (cx, NULL, &val);
+ if (!bytes)
+ return JS_FALSE;
+ if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) {
+ SWFDEC_WARNING ("trying to SetProperty %u, not allowed", id);
+ goto out;
+ }
+ if (*bytes == '\0' || *bytes == '.')
+ val = OBJECT_TO_JSVAL (cx->fp->varobj);
+ movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE);
+ if (movie == NULL) {
+ SWFDEC_WARNING ("specified target does not reference a movie clip");
+ goto out;
+ }
+ jsobj = JSVAL_TO_OBJECT (val);
+
+ if (!JS_SetProperty (cx, jsobj, properties[id], &cx->fp->sp[-1]))
+ return JS_FALSE;
+
+out:
+ cx->fp->sp -= 3;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_binary (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval lval, rval;
+ double l, r;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ if (((SwfdecScript *) cx->fp->swf)->version < 7) {
+ l = swfdec_value_to_number (cx, lval);
+ r = swfdec_value_to_number (cx, rval);
+ } else {
+ if (!swfdec_value_to_number_7 (cx, lval, &l) ||
+ !swfdec_value_to_number_7 (cx, rval, &r))
+ return JS_FALSE;
+ }
+ cx->fp->sp--;
+ switch (action) {
+ case 0x0a:
+ l = l + r;
+ break;
+ case 0x0b:
+ l = l - r;
+ break;
+ case 0x0c:
+ l = l * r;
+ break;
+ case 0x0d:
+ if (((SwfdecScript *) cx->fp->swf)->version < 5) {
+ if (r == 0) {
+ JSString *str = JS_InternString (cx, "#ERROR#");
+ if (str == NULL)
+ return JS_FALSE;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (str);
+ return JS_TRUE;
+ }
+ } else if (((SwfdecScript *) cx->fp->swf)->version < 7) {
+ if (isnan (r))
+ r = 0;
+ }
+ l = l / r;
+ break;
+ default:
+ g_assert_not_reached ();
+ return r;
+ }
+ return JS_NewNumberValue (cx, l, &cx->fp->sp[-1]);
+}
+
+static JSString *
+swfdec_action_to_string_5 (SwfdecAsContext *cx, jsval val)
+{
+ if (JSVAL_IS_VOID (val))
+ return cx->runtime->emptyString;
+ return js_ValueToString (cx, val);
+}
+
+static void
+swfdec_action_add2_5 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval rval, lval;
+ gboolean cond;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) {
+ JSString *str, *str2;
+ if (cond) {
+ str = JSVAL_TO_STRING (lval);
+ if ((str2 = swfdec_action_to_string_5 (cx, rval)) == NULL)
+ return JS_FALSE;
+ } else {
+ str2 = JSVAL_TO_STRING (rval);
+ if ((str = swfdec_action_to_string_5 (cx, lval)) == NULL)
+ return JS_FALSE;
+ }
+ str = js_ConcatStrings (cx, str, str2);
+ if (!str)
+ return JS_FALSE;
+ cx->fp->sp--;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (str);
+ } else {
+ double d, d2;
+ d = swfdec_value_to_number (cx, lval);
+ d2 = swfdec_value_to_number (cx, rval);
+ d += d2;
+ cx->fp->sp--;
+ return JS_NewNumberValue(cx, d, &cx->fp->sp[-1]);
+ }
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_add2_7 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval rval, lval;
+ gboolean cond;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) {
+ JSString *str, *str2;
+ if (cond) {
+ str = JSVAL_TO_STRING (lval);
+ if ((str2 = js_ValueToString (cx, rval)) == NULL)
+ return JS_FALSE;
+ } else {
+ str2 = JSVAL_TO_STRING (rval);
+ if ((str = js_ValueToString (cx, lval)) == NULL)
+ return JS_FALSE;
+ }
+ str = js_ConcatStrings (cx, str, str2);
+ if (!str)
+ return JS_FALSE;
+ cx->fp->sp--;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (str);
+ } else {
+ double d, d2;
+ if (!swfdec_value_to_number_7 (cx, lval, &d) ||
+ !swfdec_value_to_number_7 (cx, rval, &d2))
+ return JS_FALSE;
+ d += d2;
+ cx->fp->sp--;
+ return JS_NewNumberValue(cx, d, &cx->fp->sp[-1]);
+ }
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_get_member (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *s;
+ jsval o;
+
+ s = swfdec_js_to_string (cx, cx->fp->sp[-1]);
+ if (s == NULL)
+ return JS_FALSE;
+
+ o = cx->fp->sp[-2];
+ if (JSVAL_IS_OBJECT (o) && !JSVAL_IS_NULL (o)) {
+ if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (o), s, &cx->fp->sp[-2]))
+ return JS_FALSE;
+#ifdef SWFDEC_WARN_MISSING_PROPERTIES
+ if (cx->fp->sp[-2] == JSVAL_VOID) {
+ const JSClass *clasp = JS_GetClass (JSVAL_TO_OBJECT (o));
+ if (clasp != &js_ObjectClass) {
+ SWFDEC_WARNING ("no variable named %s:%s", clasp->name, s);
+ }
+ }
+#endif
+ } else {
+ cx->fp->sp[-2] = JSVAL_VOID;
+ }
+ cx->fp->sp--;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_set_member (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *s;
+
+ s = swfdec_js_to_string (cx, cx->fp->sp[-2]);
+ if (s == NULL)
+ return JS_FALSE;
+
+ if (JSVAL_IS_OBJECT (cx->fp->sp[-3]) && !JSVAL_IS_NULL (cx->fp->sp[-3])) {
+ if (!JS_SetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-3]), s, &cx->fp->sp[-1]))
+ return JS_FALSE;
+ }
+ cx->fp->sp -= 3;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_new_comparison_6 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval lval, rval;
+ double d, d2;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ cx->fp->sp--;
+ d = swfdec_value_to_number (cx, lval);
+ d2 = swfdec_value_to_number (cx, rval);
+ if (action == 0x48)
+ cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (d < d2);
+ else
+ cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (d > d2);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_new_comparison_7 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval lval, rval;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ cx->fp->sp--;
+ if (JSVAL_IS_VOID (rval) || JSVAL_IS_VOID (lval)) {
+ cx->fp->sp[-1] = JSVAL_VOID;
+ } else if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {
+ int comp = JS_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval));
+ cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (action == 0x48 ? comp < 0 : comp > 0);
+ } else {
+ double d, d2;
+ if (!JS_ValueToNumber(cx, lval, &d) ||
+ !JS_ValueToNumber(cx, rval, &d2))
+ return JS_FALSE;
+ cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (action == 0x48 ? d < d2 : d > d2);
+ }
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_not_4 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d;
+
+ d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+ cx->fp->sp[-1] = INT_TO_JSVAL (d == 0 ? 1 : 0);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_not_5 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d;
+
+ d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+ cx->fp->sp[-1] = d == 0 ? JSVAL_TRUE : JSVAL_FALSE;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_jump (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ if (len != 2) {
+ SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
+ return JS_FALSE;
+ }
+ cx->fp->pc += 5 + GINT16_FROM_LE (*((gint16*) data));
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_if (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d;
+
+ if (len != 2) {
+ SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
+ return JS_FALSE;
+ }
+ d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+ cx->fp->sp--;
+ if (d != 0)
+ cx->fp->pc += 5 + GINT16_FROM_LE (*((gint16*) data));
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_decrement (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d;
+
+ d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+ d--;
+ return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_increment (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d;
+
+ d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+ d++;
+ return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_get_url (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie;
+ SwfdecBits bits;
+ const char *url, *target;
+
+ swfdec_bits_init_data (&bits, data, len);
+ url = swfdec_bits_skip_string (&bits);
+ target = swfdec_bits_skip_string (&bits);
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_WARNING ("leftover bytes in GetURL action");
+ }
+ movie = swfdec_action_get_target (cx);
+ if (movie)
+ swfdec_root_movie_load (SWFDEC_ROOT_MOVIE (movie->root), url, target);
+ else
+ SWFDEC_WARNING ("no movie to load");
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_get_url2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *target, *url;
+ guint method;
+ SwfdecMovie *movie;
+
+ if (len != 1) {
+ SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len);
+ return JS_FALSE;
+ }
+ target = swfdec_js_to_string (cx, cx->fp->sp[-1]);
+ url = swfdec_js_to_string (cx, cx->fp->sp[-2]);
+ if (target == NULL || url == NULL)
+ return JS_FALSE;
+ method = data[0] >> 6;
+ if (method == 3) {
+ SWFDEC_ERROR ("GetURL method 3 invalid");
+ method = 0;
+ }
+ if (method) {
+ SWFDEC_ERROR ("FIXME: implement encoding variables using %s", method == 1 ? "GET" : "POST");
+ }
+ if (data[0] & 2) {
+ SWFDEC_ERROR ("FIXME: implement LoadTarget");
+ }
+ if (data[0] & 1) {
+ SWFDEC_ERROR ("FIXME: implement LoadVariables");
+ }
+ movie = swfdec_action_get_target (cx);
+ if (movie)
+ swfdec_root_movie_load (SWFDEC_ROOT_MOVIE (movie->root), url, target);
+ else
+ SWFDEC_WARNING ("no movie to load");
+ cx->fp->sp -= 2;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_string_add (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSString *lval, *rval;
+
+ rval = JS_ValueToString (cx, cx->fp->sp[-1]);
+ lval = JS_ValueToString (cx, cx->fp->sp[-2]);
+ if (lval == NULL || rval == NULL)
+ return FALSE;
+ lval = JS_ConcatStrings (cx, lval, rval);
+ if (lval == NULL)
+ return FALSE;
+ cx->fp->sp--;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (lval);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_push_duplicate (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ cx->fp->sp++;
+ cx->fp->sp[-1] = cx->fp->sp[-2];
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_random_number (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ gint32 max, result;
+
+ if (!JS_ValueToECMAInt32 (cx, cx->fp->sp[-1], &max))
+ return JS_FALSE;
+
+ if (max <= 0)
+ result = 0;
+ else
+ result = g_random_int_range (0, max);
+
+ return JS_NewNumberValue(cx, result, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_old_compare (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval rval, lval;
+ double l, r;
+ void cond;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ l = swfdec_value_to_number (cx, lval);
+ r = swfdec_value_to_number (cx, rval);
+ switch (action) {
+ case 0x0e:
+ cond = l == r;
+ break;
+ case 0x0f:
+ cond = l < r;
+ break;
+ default:
+ g_assert_not_reached ();
+ return JS_FALSE;
+ }
+ cx->fp->sp--;
+ if (((SwfdecScript *) cx->fp->swf)->version < 5) {
+ cx->fp->sp[-1] = INT_TO_JSVAL (cond ? 1 : 0);
+ } else {
+ cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (cond);
+ }
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_equals2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval rval, lval;
+ int ltag, rtag;
+ void cond;
+
+ rval = cx->fp->sp[-1];
+ lval = cx->fp->sp[-2];
+ ltag = JSVAL_TAG(lval);
+ rtag = JSVAL_TAG(rval);
+ if (ltag == rtag) {
+ if (ltag == JSVAL_STRING) {
+ cond = js_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)) == 0;
+ } else if (ltag == JSVAL_DOUBLE) {
+ cond = *JSVAL_TO_DOUBLE(lval) == *JSVAL_TO_DOUBLE(rval);
+ } else {
+ cond = lval == rval;
+ }
+ } else {
+ if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) {
+ cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval));
+ } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) {
+ cond = JS_FALSE;
+ } else {
+ if (ltag == JSVAL_OBJECT) {
+ if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT(lval), 0, &lval))
+ return JS_FALSE;
+ ltag = JSVAL_TAG(lval);
+ } else if (rtag == JSVAL_OBJECT) {
+ if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT(rval), 0, &rval))
+ return JS_FALSE;
+ rtag = JSVAL_TAG(rval);
+ }
+ if (ltag == JSVAL_STRING && rtag == JSVAL_STRING) {
+ cond = js_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)) == 0;
+ } else {
+ double d, d2;
+ if (!JS_ValueToNumber (cx, lval, &d) ||
+ !JS_ValueToNumber (cx, rval, &d2))
+ return JS_FALSE;
+ cond = d == d2;
+ }
+ }
+ }
+ cx->fp->sp--;
+ cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (cond);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_do_set_target (SwfdecAsContext *cx, JSObject *target)
+{
+ JSObject *with;
+
+ /* FIXME: this whole function stops working the moment it's used together
+ * with With */
+ with = js_NewObject(cx, &js_WithClass, target, cx->fp->scopeChain);
+ if (!with)
+ return JS_FALSE;
+ cx->fp->scopeChain = with;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_do_unset_target (SwfdecAsContext *cx)
+{
+ if (JS_GetClass (cx->fp->scopeChain) != &js_WithClass) {
+ SWFDEC_ERROR ("Cannot unset target: scope chain contains no with object");
+ return JS_TRUE;
+ }
+ cx->fp->scopeChain = JS_GetParent (cx, cx->fp->scopeChain);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_set_target (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval target;
+
+ if (!memchr (data, 0, len)) {
+ SWFDEC_ERROR ("SetTarget action does not specify a string");
+ return JS_FALSE;
+ }
+ if (*data == '\0')
+ return swfdec_action_do_unset_target (cx);
+ target = swfdec_js_eval (cx, NULL, (const char *) data);
+ if (!JSVAL_IS_OBJECT (target) || JSVAL_IS_NULL (target)) {
+ SWFDEC_WARNING ("target is not an object");
+ return JS_TRUE;
+ }
+ return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (target));
+}
+
+static void
+swfdec_action_set_target2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval val;
+
+ val = cx->fp->sp[-1];
+ cx->fp->sp--;
+ if (!JSVAL_IS_OBJECT (val) || JSVAL_IS_NULL (val)) {
+ SWFDEC_WARNING ("target is not an object");
+ return JS_TRUE;
+ }
+ return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (val));
+}
+
+static void
+swfdec_action_start_drag (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ guint n_args = 1;
+
+ if (!swfdec_script_ensure_stack (cx, 3))
+ return JS_FALSE;
+ if (!swfdec_eval_jsval (cx, NULL, &fp->sp[-1]))
+ return JS_FALSE;
+ if (swfdec_value_to_number (cx, fp->sp[-3])) {
+ jsval tmp;
+ if (!swfdec_script_ensure_stack (cx, 7))
+ return JS_FALSE;
+ n_args = 5;
+ /* yay for order */
+ tmp = fp->sp[-4];
+ fp->sp[-4] = fp->sp[-7];
+ fp->sp[-7] = tmp;
+ tmp = fp->sp[-6];
+ fp->sp[-6] = fp->sp[-5];
+ fp->sp[-5] = tmp;
+ }
+ if (!JSVAL_IS_OBJECT (fp->sp[-1]) || JSVAL_IS_NULL (fp->sp[-1])) {
+ fp->sp -= n_args + 2;
+ return JS_TRUE;
+ }
+ fp->sp[-3] = fp->sp[-2];
+ fp->sp[-2] = fp->sp[-1];
+ if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (fp->sp[-2]), "startDrag", &fp->sp[-1]))
+ return JS_FALSE;
+ swfdec_action_call (cx, n_args, 0);
+ fp->sp--;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_end_drag (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecPlayer *player = JS_GetContextPrivate (cx);
+ swfdec_player_set_drag_movie (player, NULL, FALSE, NULL);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_stop_sounds (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecPlayer *player = JS_GetContextPrivate (cx);
+
+ swfdec_player_stop_all_sounds (player);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_new_object (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ jsval constructor;
+ JSObject *object;
+ guint n_args;
+ const char *name;
+
+ if (!swfdec_script_ensure_stack (cx, 2))
+ return JS_FALSE;
+ constructor = fp->sp[-1];
+ name = swfdec_eval_jsval (cx, NULL, &constructor);
+ if (name == NULL)
+ return JS_FALSE;
+ if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args))
+ return JS_FALSE;
+ if (constructor == JSVAL_VOID) {
+ SWFDEC_WARNING ("no constructor for %s", name);
+ }
+ fp->sp[-1] = constructor;
+
+ if (!swfdec_js_construct_object (cx, NULL, constructor, &object))
+ return JS_FALSE;
+ if (object == NULL)
+ goto fail;
+ fp->sp[-2] = OBJECT_TO_JSVAL (object);
+ if (!swfdec_action_call (cx, n_args, JSINVOKE_CONSTRUCT))
+ return JS_FALSE;
+ fp->sp[-1] = OBJECT_TO_JSVAL (object);
+ return JS_TRUE;
+
+fail:
+ fp->sp -= n_args + 1;
+ fp->sp[-1] = JSVAL_VOID;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_new_method (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ const char *s;
+ guint32 n_args;
+ JSObject *object;
+ jsval constructor;
+
+ if (!swfdec_script_ensure_stack (cx, 3))
+ return JS_FALSE;
+ s = swfdec_js_to_string (cx, fp->sp[-1]);
+ if (s == NULL)
+ return JS_FALSE;
+ if (!JS_ValueToECMAUint32 (cx, fp->sp[-3], &n_args))
+ return JS_FALSE;
+
+ if (!JS_ValueToObject (cx, fp->sp[-2], &object))
+ return JS_FALSE;
+ if (object == NULL)
+ goto fail;
+ if (s[0] == '\0') {
+ constructor = OBJECT_TO_JSVAL (object);
+ } else {
+ if (!JS_GetProperty (cx, object, s, &constructor))
+ return JS_FALSE;
+ if (!JSVAL_IS_OBJECT (constructor)) {
+ SWFDEC_WARNING ("%s:%s is not a function", JS_GetClass (object)->name, s);
+ }
+ }
+ fp->sp[-1] = OBJECT_TO_JSVAL (constructor);
+ if (!swfdec_js_construct_object (cx, NULL, constructor, &object))
+ return JS_FALSE;
+ if (object == NULL)
+ goto fail;
+ fp->sp[-2] = OBJECT_TO_JSVAL (object);
+ if (!swfdec_action_call (cx, n_args, JSINVOKE_CONSTRUCT))
+ return JS_FALSE;
+ fp->sp[-1] = OBJECT_TO_JSVAL (object);
+ return JS_TRUE;
+
+fail:
+ fp->sp -= 2 + n_args;
+ fp->sp[-1] = JSVAL_VOID;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_init_object (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ JSObject *object;
+ guint n_args;
+ gulong i;
+
+ if (!JS_ValueToECMAUint32 (cx, fp->sp[-1], &n_args))
+ return JS_FALSE;
+ if (!swfdec_script_ensure_stack (cx, 2 * n_args + 1))
+ return JS_FALSE;
+
+ object = JS_NewObject (cx, &js_ObjectClass, NULL, NULL);
+ if (object == NULL)
+ return JS_FALSE;
+ for (i = 0; i < n_args; i++) {
+ const char *s = swfdec_js_to_string (cx, fp->sp[-3 - 2 * i]);
+ if (s == NULL)
+ return JS_FALSE;
+ if (!JS_SetProperty (cx, object, s, &fp->sp[-2 - 2 * i]))
+ return JS_FALSE;
+ }
+ fp->sp -= 2 * n_args;
+ fp->sp[-1] = OBJECT_TO_JSVAL (object);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_init_array (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSStackFrame *fp = cx->fp;
+ JSObject *array;
+ int i, j;
+ guint n_items;
+
+ if (!JS_ValueToECMAUint32 (cx, fp->sp[-1], &n_items))
+ return JS_FALSE;
+ if (!swfdec_script_ensure_stack (cx, n_items + 1))
+ return JS_FALSE;
+
+ /* items are the wrong order on the stack */
+ j = - 1 - n_items;
+ for (i = - 2; i > j; i--, j++) {
+ jsval tmp = fp->sp[i];
+ fp->sp[i] = fp->sp[j];
+ fp->sp[j] = tmp;
+ }
+ array = JS_NewArrayObject (cx, n_items, fp->sp - n_items - 1);
+ if (array == NULL)
+ return JS_FALSE;
+ fp->sp -= n_items;
+ fp->sp[-1] = OBJECT_TO_JSVAL (array);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_define_function (SwfdecAsContext *cx, guint action,
+ const guint8 *data, guint len)
+{
+ const char *function_name;
+ guint i, n_args, size;
+ SwfdecBits bits;
+ JSFunction *fun;
+ SwfdecScript *script;
+ JSObject *scope;
+ gboolean has_preloads = FALSE;
+ guint flags = 0;
+ guint8 *preloads = NULL;
+ gboolean v2 = (action == 0x8e);
+
+ swfdec_bits_init_data (&bits, data, len);
+ function_name = swfdec_bits_skip_string (&bits);
+ if (function_name == NULL) {
+ SWFDEC_ERROR ("could not parse function name");
+ return JS_FALSE;
+ }
+ n_args = swfdec_bits_get_u16 (&bits);
+ scope = cx->fp->scopeChain;
+ script = cx->fp->swf;
+ if (script->version == 5) {
+ /* In Flash 5 there's only the root scope as a parent scope */
+ JSObject *parent;
+ /* FIXME: this implementation is hacky (but it works) */
+ while (JS_GetClass (scope) == &js_CallClass && (parent = JS_GetParent (cx, scope)))
+ scope = parent;
+ }
+ if (*function_name == '\0') {
+ /* anonymous function */
+ fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA | JSFUN_HEAVYWEIGHT,
+ scope, NULL);
+ } else {
+ /* named function */
+ fun = JS_NewFunction (cx, NULL, n_args, JSFUN_HEAVYWEIGHT,
+ scope, function_name);
+ }
+ if (fun == NULL)
+ return JS_FALSE;
+ if (v2) {
+ script->n_registers = swfdec_bits_get_u8 (&bits) + 1;
+ flags = swfdec_bits_get_u16 (&bits);
+ preloads = g_new0 (guint8, n_args);
+ } else {
+ script->n_registers = 5;
+ }
+ fun->nvars = script->n_registers;
+ for (i = 0; i < n_args; i++) {
+ JSAtom *atom;
+ const char *arg_name;
+ if (v2) {
+ guint preload = swfdec_bits_get_u8 (&bits);
+ if (preload && preload >= script->n_registers) {
+ SWFDEC_ERROR ("argument %u is preloaded into register %u out of %u",
+ i, preload, script->n_registers);
+ return JS_FALSE;
+ }
+ if (preload != 0) {
+ preloads[i] = preload;
+ swfdec_bits_skip_string (&bits);
+ has_preloads = TRUE;
+ continue;
+ }
+ }
+ arg_name = swfdec_bits_skip_string (&bits);
+ if (arg_name == NULL || *arg_name == '\0') {
+ SWFDEC_ERROR ("empty argument name not allowed");
+ return JS_FALSE;
+ }
+ /* FIXME: check duplicate arguments */
+ atom = js_Atomize (cx, arg_name, strlen (arg_name), 0);
+ if (atom == NULL)
+ return JS_FALSE;
+ if (!js_AddNativeProperty (cx, fun->object, (jsid) atom,
+ js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT,
+ JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED,
+ SPROP_HAS_SHORTID, i)) {
+ return JS_FALSE;
+ }
+ }
+ if (preloads && !has_preloads) {
+ g_free (preloads);
+ preloads = NULL;
+ }
+ size = swfdec_bits_get_u16 (&bits);
+ /* check the script can be created */
+ if (script->buffer->data + script->buffer->length < cx->fp->pc + 3 + len + size) {
+ SWFDEC_ERROR ("size of function is too big");
+ return FALSE;
+ } else {
+ /* create the script */
+ const char *name = NULL;
+ SwfdecBuffer *buffer = swfdec_buffer_new_subbuffer (script->buffer,
+ cx->fp->pc + 3 + len - script->buffer->data, size);
+ swfdec_bits_init (&bits, buffer);
+ if (*function_name) {
+ name = function_name;
+ } else if (cx->fp->sp > cx->fp->spbase) {
+ /* 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.
+ */
+ if (JSVAL_IS_STRING (cx->fp->sp[-1]))
+ name = JS_GetStringBytes (JSVAL_TO_STRING (cx->fp->sp[-1]));
+ }
+ if (name == NULL)
+ name = "unnamed_function";
+ script = swfdec_script_new (&bits, name, ((SwfdecScript *) cx->fp->swf)->version);
+ swfdec_buffer_unref (buffer);
+ }
+ if (script == NULL) {
+ SWFDEC_ERROR ("failed to create script");
+ g_free (preloads);
+ return JS_FALSE;
+ }
+ if (cx->fp->constant_pool) {
+ script->constant_pool = swfdec_constant_pool_get_area (cx->fp->swf,
+ cx->fp->constant_pool);
+ }
+ script->flags = flags;
+ script->preloads = preloads;
+ fun->swf = script;
+ swfdec_script_add_to_player (script, JS_GetContextPrivate (cx));
+ /* attach the function */
+ if (*function_name == '\0') {
+ if (cx->fp->sp >= cx->fp->spend) {
+ SWFDEC_ERROR ("not enough stack space available");
+ return JS_FALSE;
+ }
+ *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object);
+ } else {
+ jsval val = OBJECT_TO_JSVAL (fun->object);
+ if (!JS_SetProperty (cx, cx->fp->varobj, function_name, &val))
+ return JS_FALSE;
+ }
+
+ /* update current context */
+ cx->fp->pc += 3 + len + size;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_bitwise (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ guint32 a, b;
+ double d;
+
+ if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &a) ||
+ !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &b))
+ return JS_FALSE;
+
+ switch (action) {
+ case 0x60:
+ d = (int) (a & b);
+ break;
+ case 0x61:
+ d = (int) (a | b);
+ break;
+ case 0x62:
+ d = (int) (a ^ b);
+ break;
+ default:
+ g_assert_not_reached ();
+ return JS_FALSE;
+ }
+
+ cx->fp->sp--;
+ return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_shift (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ guint32 amount, value;
+ double d;
+
+ if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &amount) ||
+ !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &value))
+ return JS_FALSE;
+
+ amount &= 31;
+ switch (action) {
+ case 0x63:
+ d = value << amount;
+ break;
+ case 0x64:
+ d = ((gint) value) >> amount;
+ break;
+ case 0x65:
+ d = ((guint) value) >> amount;
+ break;
+ default:
+ g_assert_not_reached ();
+ return JS_FALSE;
+ }
+
+ cx->fp->sp--;
+ return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_to_integer (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+
+ return JS_NewNumberValue (cx, (int) d, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_target_path (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecMovie *movie = swfdec_scriptable_from_jsval (cx, cx->fp->sp[-1], SWFDEC_TYPE_MOVIE);
+
+ if (movie == NULL) {
+ cx->fp->sp[-1] = JSVAL_VOID;
+ } else {
+ char *s = swfdec_movie_get_path (movie);
+ JSString *string = JS_NewStringCopyZ (cx, s);
+ g_free (s);
+ if (string == NULL)
+ return JS_FALSE;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (string);
+ }
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_define_local (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *name;
+
+ g_assert (cx->fp->scopeChain != NULL);
+ name = swfdec_js_to_string (cx, cx->fp->sp[-2]);
+ if (name == NULL)
+ return JS_FALSE;
+ if (!JS_SetProperty (cx, cx->fp->scopeChain, name, &cx->fp->sp[-1]))
+ return JS_FALSE;
+ cx->fp->sp -= 2;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_define_local2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *name;
+ jsval val = JSVAL_VOID;
+
+ g_assert (cx->fp->scopeChain != NULL);
+ name = swfdec_js_to_string (cx, cx->fp->sp[-1]);
+ if (name == NULL)
+ return JS_FALSE;
+ if (!JS_SetProperty (cx, cx->fp->scopeChain, name, &val))
+ return JS_FALSE;
+ cx->fp->sp--;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_return (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecScript *script = cx->fp->swf;
+
+ cx->fp->rval = cx->fp->sp[-1];
+ cx->fp->pc = script->buffer->data + script->buffer->length;
+ cx->fp->sp--;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_delete (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *name;
+
+ cx->fp->sp -= 2;
+ name = swfdec_js_to_string (cx, cx->fp->sp[1]);
+ if (name == NULL)
+ return JS_FALSE;
+ if (!JSVAL_IS_OBJECT (cx->fp->sp[0]))
+ return JS_TRUE;
+ return JS_DeleteProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[0]), name);
+}
+
+static void
+swfdec_action_delete2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ const char *name;
+ JSObject *obj, *pobj;
+ JSProperty *prop;
+ JSAtom *atom;
+
+ cx->fp->sp -= 1;
+ name = swfdec_js_to_string (cx, cx->fp->sp[1]);
+ if (name == NULL)
+ return JS_FALSE;
+ if (!(atom = js_Atomize (cx, name, strlen (name), 0)) ||
+ !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop))
+ return JS_FALSE;
+ if (!pobj)
+ return JS_TRUE;
+ return JS_DeleteProperty (cx, pobj, name);
+}
+
+static void
+swfdec_action_store_register (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ if (len != 1) {
+ SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len);
+ return JS_FALSE;
+ }
+ if (!swfdec_action_has_register (cx, *data)) {
+ SWFDEC_ERROR ("Cannot store into register %u, not enough registers", (guint) *data);
+ return JS_FALSE;
+ }
+ cx->fp->vars[*data] = cx->fp->sp[-1];
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_modulo_5 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double x, y;
+
+ x = swfdec_value_to_number (cx, cx->fp->sp[-1]);
+ y = swfdec_value_to_number (cx, cx->fp->sp[-2]);
+ cx->fp->sp--;
+ errno = 0;
+ x = fmod (x, y);
+ if (errno != 0) {
+ cx->fp->sp[-1] = DOUBLE_TO_JSVAL (cx->runtime->jsNaN);
+ return JS_TRUE;
+ } else {
+ return JS_NewNumberValue (cx, x, &cx->fp->sp[-1]);
+ }
+}
+
+static void
+swfdec_action_modulo_7 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double x, y;
+
+ if (!swfdec_value_to_number_7 (cx, cx->fp->sp[-1], &x) ||
+ !swfdec_value_to_number_7 (cx, cx->fp->sp[-2], &y))
+ return JS_FALSE;
+ cx->fp->sp--;
+ errno = 0;
+ x = fmod (x, y);
+ if (errno != 0) {
+ cx->fp->sp[-1] = DOUBLE_TO_JSVAL (cx->runtime->jsNaN);
+ return JS_TRUE;
+ } else {
+ return JS_NewNumberValue (cx, x, &cx->fp->sp[-1]);
+ }
+}
+
+static void
+swfdec_action_swap (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval tmp = cx->fp->sp[-2];
+ cx->fp->sp[-2] = cx->fp->sp[-1];
+ cx->fp->sp[-1] = tmp;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_to_number (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ double d;
+ if (!JS_ValueToNumber (cx, cx->fp->sp[-1], &d))
+ return JS_FALSE;
+ return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
+}
+
+static void
+swfdec_action_to_string (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSString *s;
+ s = JS_ValueToString(cx, cx->fp->sp[-1]);
+ if (!s)
+ return JS_FALSE;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (s);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_type_of (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval val;
+ const char *type;
+ JSString *string;
+
+ val = cx->fp->sp[-1];
+ if (JSVAL_IS_NUMBER (val)) {
+ type = "number";
+ } else if (JSVAL_IS_BOOLEAN (val)) {
+ type = "boolean";
+ } else if (JSVAL_IS_STRING (val)) {
+ type = "string";
+ } else if (JSVAL_IS_VOID (val)) {
+ type = "undefined";
+ } else if (JSVAL_IS_NULL (val)) {
+ type = "null";
+ } else if (JSVAL_IS_OBJECT (val)) {
+ JSObject *obj = JSVAL_TO_OBJECT (val);
+ if (swfdec_js_is_movieclip (cx, obj)) {
+ type = "movieclip";
+ } else if (JS_ObjectIsFunction (cx, obj)) {
+ type = "function";
+ } else {
+ type = "object";
+ }
+ } else {
+ g_assert_not_reached ();
+ return JS_FALSE;
+ }
+ /* can't use InternString here because of case sensitivity issues */
+ string = JS_NewStringCopyZ (cx, type);
+ if (string == NULL)
+ return JS_FALSE;
+ cx->fp->sp[-1] = STRING_TO_JSVAL (string);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_get_time (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecPlayer *player = JS_GetContextPrivate (cx);
+
+ *cx->fp->sp++ = INT_TO_JSVAL ((int) SWFDEC_TICKS_TO_MSECS (player->time));
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_extends (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ jsval superclass, subclass, proto;
+ JSObject *prototype;
+
+ superclass = cx->fp->sp[-1];
+ subclass = cx->fp->sp[-2];
+ cx->fp->sp -= 2;
+ if (!JSVAL_IS_OBJECT (superclass) || superclass == JSVAL_NULL ||
+ !JSVAL_IS_OBJECT (subclass) || subclass == JSVAL_NULL) {
+ SWFDEC_ERROR ("superclass or subclass aren't objects");
+ return JS_TRUE;
+ }
+ if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (superclass), "prototype", &proto) ||
+ !JSVAL_IS_OBJECT (proto))
+ return JS_FALSE;
+ prototype = JS_NewObject (cx, NULL, JSVAL_TO_OBJECT (proto), NULL);
+ if (prototype == NULL)
+ return JS_FALSE;
+ proto = OBJECT_TO_JSVAL (prototype);
+ if (!JS_SetProperty (cx, prototype, "__constructor__", &superclass) ||
+ !JS_SetProperty (cx, JSVAL_TO_OBJECT (subclass), "prototype", &proto))
+ return JS_FALSE;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_enumerate2 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ JSObject *obj;
+ JSIdArray *array;
+ guint i;
+
+ if (!JSVAL_IS_OBJECT (cx->fp->sp[-1]) || cx->fp->sp[-1] == JSVAL_NULL) {
+ SWFDEC_ERROR ("Enumerate2 called without an object");
+ cx->fp->sp[-1] = JSVAL_NULL;
+ return JS_TRUE;
+ }
+ obj = JSVAL_TO_OBJECT (cx->fp->sp[-1]);
+ cx->fp->sp[-1] = JSVAL_NULL;
+ array = JS_Enumerate (cx, obj);
+ if (!array)
+ return JS_FALSE;
+ if ((guint) (cx->fp->spend - cx->fp->sp) < array->length) {
+ SWFDEC_ERROR ("FIXME: not enough stack space, need %u, got %td",
+ array->length, cx->fp->spend - cx->fp->sp);
+ JS_DestroyIdArray (cx, array);
+ return JS_FALSE;
+ }
+ for (i = 0; i < array->length; i++) {
+ if (!JS_IdToValue (cx, array->vector[i], cx->fp->sp++)) {
+ JS_DestroyIdArray (cx, array);
+ return JS_FALSE;
+ }
+ }
+ JS_DestroyIdArray (cx, array);
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_logical_5 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ void l, r;
+
+ l = swfdec_value_to_boolean_5 (cx, cx->fp->sp[-1]);
+ r = swfdec_value_to_boolean_5 (cx, cx->fp->sp[-2]);
+
+ cx->fp->sp--;
+ if (action == 0x10)
+ cx->fp->sp[-1] = l && r ? JSVAL_TRUE : JSVAL_FALSE;
+ else
+ cx->fp->sp[-1] = l || r ? JSVAL_TRUE : JSVAL_FALSE;
+ return JS_TRUE;
+}
+
+static void
+swfdec_action_logical_7 (SwfdecAsContext *cx, guint action, const guint8 *data, guint len)
+{
+ void l, r;
+
+ l = swfdec_value_to_boolean_7 (cx, cx->fp->sp[-1]);
+ r = swfdec_value_to_boolean_7 (cx, cx->fp->sp[-2]);
+
+ cx->fp->sp--;
+ if (action == 0x10)
+ cx->fp->sp[-1] = l && r ? JSVAL_TRUE : JSVAL_FALSE;
+ else
+ cx->fp->sp[-1] = l || r ? JSVAL_TRUE : JSVAL_FALSE;
+ return JS_TRUE;
+}
+
+/*** PRINT FUNCTIONS ***/
+
+static char *
+swfdec_action_print_store_register (guint action, const guint8 *data, guint len)
+{
+ if (len != 1) {
+ SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len);
+ return NULL;
+ }
+ return g_strdup_printf ("StoreRegister %u", (guint) *data);
+}
+
+static char *
+swfdec_action_print_set_target (guint action, const guint8 *data, guint len)
+{
+ if (!memchr (data, 0, len)) {
+ SWFDEC_ERROR ("SetTarget action does not specify a string");
+ return JS_FALSE;
+ }
+ return g_strconcat ("SetTarget ", data, NULL);
+}
+
+static char *
+swfdec_action_print_define_function (guint action, const guint8 *data, guint len)
+{
+ SwfdecBits bits;
+ GString *string;
+ const char *function_name;
+ guint i, n_args, size;
+ gboolean v2 = (action == 0x8e);
+
+ string = g_string_new (v2 ? "DefineFunction2 " : "DefineFunction ");
+ swfdec_bits_init_data (&bits, data, len);
+ function_name = swfdec_bits_get_string (&bits);
+ if (function_name == NULL) {
+ SWFDEC_ERROR ("could not parse function name");
+ g_string_free (string, TRUE);
+ return NULL;
+ }
+ if (*function_name) {
+ g_string_append (string, function_name);
+ g_string_append_c (string, ' ');
+ }
+ n_args = swfdec_bits_get_u16 (&bits);
+ g_string_append_c (string, '(');
+ if (v2) {
+ /* n_regs = */ swfdec_bits_get_u8 (&bits);
+ /* flags = */ swfdec_bits_get_u16 (&bits);
+ }
+
+ for (i = 0; i < n_args; i++) {
+ guint preload;
+ const char *arg_name;
+ if (v2)
+ preload = swfdec_bits_get_u8 (&bits);
+ else
+ preload = 0;
+ arg_name = swfdec_bits_get_string (&bits);
+ if (preload == 0 && (arg_name == NULL || *arg_name == '\0')) {
+ SWFDEC_ERROR ("empty argument name not allowed");
+ g_string_free (string, TRUE);
+ return NULL;
+ }
+ if (i)
+ g_string_append (string, ", ");
+ if (preload)
+ g_string_append_printf (string, "PRELOAD %u", preload);
+ else
+ g_string_append (string, arg_name);
+ }
+ g_string_append_c (string, ')');
+ size = swfdec_bits_get_u16 (&bits);
+ g_string_append_printf (string, " %u", size);
+ return g_string_free (string, FALSE);
+}
+
+static char *
+swfdec_action_print_get_url2 (guint action, const guint8 *data, guint len)
+{
+ guint method;
+
+ if (len != 1) {
+ SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len);
+ return NULL;
+ }
+ method = data[0] >> 6;
+ if (method == 3) {
+ SWFDEC_ERROR ("GetURL method 3 invalid");
+ method = 0;
+ }
+ if (method) {
+ SWFDEC_ERROR ("FIXME: implement encoding variables using %s", method == 1 ? "GET" : "POST");
+ }
+ return g_strdup_printf ("GetURL2%s%s%s", method == 0 ? "" : (method == 1 ? " GET" : " POST"),
+ data[0] & 2 ? " LoadTarget" : "", data[0] & 1 ? " LoadVariables" : "");
+}
+
+static char *
+swfdec_action_print_get_url (guint action, const guint8 *data, guint len)
+{
+ SwfdecBits bits;
+ const char *url, *target;
+
+ swfdec_bits_init_data (&bits, data, len);
+ url = swfdec_bits_skip_string (&bits);
+ target = swfdec_bits_skip_string (&bits);
+ if (swfdec_bits_left (&bits)) {
+ SWFDEC_WARNING ("leftover bytes in GetURL action");
+ }
+ return g_strdup_printf ("GetURL %s %s", url, target);
+}
+
+static char *
+swfdec_action_print_if (guint action, const guint8 *data, guint len)
+{
+ if (len != 2) {
+ SWFDEC_ERROR ("If action length invalid (is %u, should be 2", len);
+ return NULL;
+ }
+ return g_strdup_printf ("If %d", GINT16_FROM_LE (*((gint16*) data)));
+}
+
+static char *
+swfdec_action_print_jump (guint action, const guint8 *data, guint len)
+{
+ if (len != 2) {
+ SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
+ return NULL;
+ }
+ return g_strdup_printf ("Jump %d", GINT16_FROM_LE (*((gint16*) data)));
+}
+
+static char *
+swfdec_action_print_push (guint action, const guint8 *data, guint len)
+{
+ gboolean first = TRUE;
+ SwfdecBits bits;
+ GString *string = g_string_new ("Push");
+
+ swfdec_bits_init_data (&bits, data, len);
+ while (swfdec_bits_left (&bits)) {
+ guint type = swfdec_bits_get_u8 (&bits);
+ if (first)
+ g_string_append (string, " ");
+ else
+ g_string_append (string, ", ");
+ first = FALSE;
+ switch (type) {
+ case 0: /* string */
+ {
+ const char *s = swfdec_bits_skip_string (&bits);
+ if (!s) {
+ g_string_free (string, TRUE);
+ return NULL;
+ }
+ g_string_append_c (string, '"');
+ g_string_append (string, s);
+ g_string_append_c (string, '"');
+ break;
+ }
+ case 1: /* float */
+ g_string_append_printf (string, "%g", swfdec_bits_get_float (&bits));
+ break;
+ case 2: /* null */
+ g_string_append (string, "null");
+ break;
+ case 3: /* undefined */
+ g_string_append (string, "void");
+ break;
+ case 4: /* register */
+ g_string_append_printf (string, "Register %u", swfdec_bits_get_u8 (&bits));
+ break;
+ case 5: /* boolean */
+ g_string_append (string, swfdec_bits_get_u8 (&bits) ? "True" : "False");
+ break;
+ case 6: /* double */
+ g_string_append_printf (string, "%g", swfdec_bits_get_double (&bits));
+ break;
+ case 7: /* 32bit int */
+ g_string_append_printf (string, "%d", swfdec_bits_get_u32 (&bits));
+ break;
+ case 8: /* 8bit ConstantPool address */
+ g_string_append_printf (string, "Pool %u", swfdec_bits_get_u8 (&bits));
+ break;
+ case 9: /* 16bit ConstantPool address */
+ g_string_append_printf (string, "Pool %u", swfdec_bits_get_u16 (&bits));
+ break;
+ default:
+ SWFDEC_ERROR ("Push: type %u not implemented", type);
+ return JS_FALSE;
+ }
+ }
+ return g_string_free (string, FALSE);
+}
+
+/* NB: constant pool actions are special in that they are called at init time */
+static char *
+swfdec_action_print_constant_pool (guint action, const guint8 *data, guint len)
+{
+ guint i;
+ GString *string;
+ SwfdecConstantPool *pool;
+
+ pool = swfdec_constant_pool_new_from_action (data, len);
+ if (pool == NULL)
+ return JS_FALSE;
+ string = g_string_new ("ConstantPool");
+ for (i = 0; i < swfdec_constant_pool_size (pool); i++) {
+ g_string_append (string, i ? ", " : " ");
+ g_string_append (string, swfdec_constant_pool_get (pool, i));
+ g_string_append_printf (string, " (%u)", i);
+ }
+ return g_string_free (string, FALSE);
+}
+
+static char *
+swfdec_action_print_wait_for_frame2 (guint action, const guint8 *data, guint len)
+{
+ if (len != 1) {
+ SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
+ return NULL;
+ }
+ return g_strdup_printf ("WaitForFrame2 %u", (guint) *data);
+}
+
+static char *
+swfdec_action_print_goto_frame2 (guint action, const guint8 *data, guint len)
+{
+ gboolean play, bias;
+ SwfdecBits bits;
+
+ swfdec_bits_init_data (&bits, data, len);
+ if (swfdec_bits_getbits (&bits, 6)) {
+ SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
+ }
+ bias = swfdec_bits_getbit (&bits);
+ play = swfdec_bits_getbit (&bits);
+ if (bias) {
+ return g_strdup_printf ("GotoFrame2 %s +%u", play ? "play" : "stop",
+ swfdec_bits_get_u16 (&bits));
+ } else {
+ return g_strdup_printf ("GotoFrame2 %s", play ? "play" : "stop");
+ }
+}
+#endif
+
+static char *
+swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len)
+{
+ guint frame;
+
+ if (len != 2)
+ return NULL;
+
+ frame = GUINT16_FROM_LE (*((guint16 *) data));
+ return g_strdup_printf ("GotoFrame %u", frame);
+}
+
+static char *
+swfdec_action_print_goto_label (guint action, const guint8 *data, guint len)
+{
+ if (!memchr (data, 0, len)) {
+ SWFDEC_ERROR ("GotoLabel action does not specify a string");
+ return NULL;
+ }
+
+ return g_strdup_printf ("GotoLabel %s", data);
+}
+
+static char *
+swfdec_action_print_wait_for_frame (guint action, const guint8 *data, guint len)
+{
+ guint frame, jump;
+
+ if (len != 3)
+ return NULL;
+
+ frame = GUINT16_FROM_LE (*((guint16 *) data));
+ jump = data[2];
+ return g_strdup_printf ("WaitForFrame %u %u", frame, jump);
+}
+
+/*** BIG FUNCTION TABLE ***/
+
+const SwfdecActionSpec swfdec_as_actions[256] = {
+ /* version 3 */
+ [SWFDEC_AS_ACTION_NEXT_FRAME] = { "NextFrame", NULL, 0, 0, { swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame } },
+ [SWFDEC_AS_ACTION_PREVIOUS_FRAME] = { "PreviousFrame", NULL, 0, 0, { swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame } },
+ [SWFDEC_AS_ACTION_PLAY] = { "Play", NULL, 0, 0, { swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play } },
+ [SWFDEC_AS_ACTION_STOP] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } },
+#if 0
+ [0x08] = { "ToggleQuality", NULL },
+ [0x09] = { "StopSounds", NULL, 0, 0, { swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds } },
+ /* version 4 */
+ [0x0a] = { "Add", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
+ [0x0b] = { "Subtract", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
+ [0x0c] = { "Multiply", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
+ [0x0d] = { "Divide", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
+ [0x0e] = { "Equals", NULL, 2, 1, { NULL, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare } },
+ [0x0f] = { "Less", NULL, 2, 1, { NULL, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare } },
+ [0x10] = { "And", NULL, 2, 1, { NULL, /* FIXME */NULL, swfdec_action_logical_5, swfdec_action_logical_5, swfdec_action_logical_7 } },
+ [0x11] = { "Or", NULL, 2, 1, { NULL, /* FIXME */NULL, swfdec_action_logical_5, swfdec_action_logical_5, swfdec_action_logical_7 } },
+ [0x12] = { "Not", NULL, 1, 1, { NULL, swfdec_action_not_4, swfdec_action_not_5, swfdec_action_not_5, swfdec_action_not_5 } },
+ [0x13] = { "StringEquals", NULL },
+ [0x14] = { "StringLength", NULL },
+ [0x15] = { "StringExtract", NULL },
+ [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } },
+ [0x18] = { "ToInteger", NULL, 1, 1, { NULL, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer } },
+ [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } },
+ [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } },
+ [0x20] = { "SetTarget2", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } },
+ [0x21] = { "StringAdd", NULL, 2, 1, { NULL, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add } },
+ [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } },
+ [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } },
+ [0x24] = { "CloneSprite", NULL },
+ [0x25] = { "RemoveSprite", NULL },
+ [0x26] = { "Trace", NULL, 1, 0, { NULL, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace } },
+ [0x27] = { "StartDrag", NULL, -1, 0, { NULL, swfdec_action_start_drag, swfdec_action_start_drag, swfdec_action_start_drag, swfdec_action_start_drag } },
+ [0x28] = { "EndDrag", NULL, 0, 0, { NULL, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag } },
+ [0x29] = { "StringLess", NULL },
+ /* version 7 */
+ [0x2a] = { "Throw", NULL },
+ [0x2b] = { "Cast", NULL },
+ [0x2c] = { "Implements", NULL },
+ /* version 4 */
+ [0x30] = { "RandomNumber", NULL, 1, 1, { NULL, swfdec_action_random_number, swfdec_action_random_number, swfdec_action_random_number, swfdec_action_random_number } },
+ [0x31] = { "MBStringLength", NULL },
+ [0x32] = { "CharToAscii", NULL },
+ [0x33] = { "AsciiToChar", NULL },
+ [0x34] = { "GetTime", NULL, 0, 1, { NULL, swfdec_action_get_time, swfdec_action_get_time, swfdec_action_get_time, swfdec_action_get_time } },
+ [0x35] = { "MBStringExtract", NULL },
+ [0x36] = { "MBCharToAscii", NULL },
+ [0x37] = { "MVAsciiToChar", NULL },
+ /* version 5 */
+ [0x3a] = { "Delete", NULL, 2, 0, { NULL, NULL, swfdec_action_delete, swfdec_action_delete, swfdec_action_delete } },
+ [0x3b] = { "Delete2", NULL, 1, 0, { NULL, NULL, swfdec_action_delete2, swfdec_action_delete2, swfdec_action_delete2 } },
+ [0x3c] = { "DefineLocal", NULL, 2, 0, { NULL, NULL, swfdec_action_define_local, swfdec_action_define_local, swfdec_action_define_local } },
+ [0x3d] = { "CallFunction", NULL, -1, 1, { NULL, NULL, swfdec_action_call_function, swfdec_action_call_function, swfdec_action_call_function } },
+ [0x3e] = { "Return", NULL, 1, 0, { NULL, NULL, swfdec_action_return, swfdec_action_return, swfdec_action_return } },
+ [0x3f] = { "Modulo", NULL, 2, 1, { NULL, NULL, swfdec_action_modulo_5, swfdec_action_modulo_5, swfdec_action_modulo_7 } },
+ [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } },
+ [0x41] = { "DefineLocal2", NULL, 1, 0, { NULL, NULL, swfdec_action_define_local2, swfdec_action_define_local2, swfdec_action_define_local2 } },
+ [0x42] = { "InitArray", NULL, -1, 1, { NULL, NULL, swfdec_action_init_array, swfdec_action_init_array, swfdec_action_init_array } },
+ [0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } },
+ [0x44] = { "TypeOf", NULL, 1, 1, { NULL, NULL, swfdec_action_type_of, swfdec_action_type_of, swfdec_action_type_of } },
+ [0x45] = { "TargetPath", NULL, 1, 1, { NULL, NULL, swfdec_action_target_path, swfdec_action_target_path, swfdec_action_target_path } },
+ [0x46] = { "Enumerate", NULL },
+ [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } },
+ [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } },
+ [0x49] = { "Equals2", NULL, 2, 1, { NULL, NULL, swfdec_action_equals2, swfdec_action_equals2, swfdec_action_equals2 } },
+ [0x4a] = { "ToNumber", NULL, 1, 1, { NULL, NULL, swfdec_action_to_number, swfdec_action_to_number, swfdec_action_to_number } },
+ [0x4b] = { "ToString", NULL, 1, 1, { NULL, NULL, swfdec_action_to_string, swfdec_action_to_string, swfdec_action_to_string } },
+ [0x4c] = { "PushDuplicate", NULL, 1, 2, { NULL, NULL, swfdec_action_push_duplicate, swfdec_action_push_duplicate, swfdec_action_push_duplicate } },
+ [0x4d] = { "Swap", NULL, 2, 2, { NULL, NULL, swfdec_action_swap, swfdec_action_swap, swfdec_action_swap } },
+ [0x4e] = { "GetMember", NULL, 2, 1, { NULL, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member } },
+ [0x4f] = { "SetMember", NULL, 3, 0, { NULL, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member } },
+ [0x50] = { "Increment", NULL, 1, 1, { NULL, NULL, swfdec_action_increment, swfdec_action_increment, swfdec_action_increment } },
+ [0x51] = { "Decrement", NULL, 1, 1, { NULL, NULL, swfdec_action_decrement, swfdec_action_decrement, swfdec_action_decrement } },
+ [0x52] = { "CallMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_call_method, swfdec_action_call_method, swfdec_action_call_method } },
+ [0x53] = { "NewMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_new_method, swfdec_action_new_method, swfdec_action_new_method } },
+ /* version 6 */
+ [0x54] = { "InstanceOf", NULL },
+ [0x55] = { "Enumerate2", NULL, 1, -1, { NULL, NULL, NULL, swfdec_action_enumerate2, swfdec_action_enumerate2 } },
+ /* version 5 */
+ [0x60] = { "BitAnd", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } },
+ [0x61] = { "BitOr", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } },
+ [0x62] = { "BitXor", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } },
+ [0x63] = { "BitLShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } },
+ [0x64] = { "BitRShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } },
+ [0x65] = { "BitURShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } },
+ /* version 6 */
+ [0x66] = { "StrictEquals", NULL },
+ [0x67] = { "Greater", NULL, 2, 1, { NULL, NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } },
+ [0x68] = { "StringGreater", NULL },
+ /* version 7 */
+ [0x69] = { "Extends", NULL, 2, 0, { NULL, NULL, NULL, NULL, swfdec_action_extends } },
+
+ /* version 3 */
+#endif
+ [SWFDEC_AS_ACTION_GOTO_FRAME] = { "GotoFrame", swfdec_action_print_goto_frame, 0, 0, { swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame } },
+#if 0
+ [0x83] = { "GetURL", swfdec_action_print_get_url, 0, 0, { swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url } },
+ /* version 5 */
+ [0x87] = { "StoreRegister", swfdec_action_print_store_register, 1, 1, { NULL, NULL, swfdec_action_store_register, swfdec_action_store_register, swfdec_action_store_register } },
+ [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } },
+ /* version 3 */
+#endif
+ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } },
+#if 0
+ [0x8b] = { "SetTarget", swfdec_action_print_set_target, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } },
+#endif
+ [SWFDEC_AS_ACTION_GOTO_LABEL] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } },
+#if 0
+ /* version 4 */
+ [0x8d] = { "WaitForFrame2", swfdec_action_print_wait_for_frame2, 1, 0, { NULL, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2 } },
+ /* version 7 */
+ [0x8e] = { "DefineFunction2", swfdec_action_print_define_function, 0, -1, { NULL, NULL, NULL, swfdec_action_define_function, swfdec_action_define_function } },
+ [0x8f] = { "Try", NULL },
+ /* version 5 */
+ [0x94] = { "With", NULL },
+ /* version 4 */
+ [0x96] = { "Push", swfdec_action_print_push, 0, -1, { NULL, swfdec_action_push, swfdec_action_push, swfdec_action_push, swfdec_action_push } },
+ [0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } },
+ [0x9a] = { "GetURL2", swfdec_action_print_get_url2, 2, 0, { NULL, swfdec_action_get_url2, swfdec_action_get_url2, swfdec_action_get_url2, swfdec_action_get_url2 } },
+ /* version 5 */
+ [0x9b] = { "DefineFunction", swfdec_action_print_define_function, 0, -1, { NULL, NULL, swfdec_action_define_function, swfdec_action_define_function, swfdec_action_define_function } },
+ /* version 4 */
+ [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } },
+ [0x9e] = { "Call", NULL },
+ [0x9f] = { "GotoFrame2", swfdec_action_print_goto_frame2, 1, 0, { NULL, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2 } }
+#endif
+};
+
diff --git a/libswfdec/swfdec_as_interpret.h b/libswfdec/swfdec_as_interpret.h
new file mode 100644
index 0000000..b388db0
--- /dev/null
+++ b/libswfdec/swfdec_as_interpret.h
@@ -0,0 +1,45 @@
+/* SwfdecAs
+ * 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_AS_INTERPRET_H_
+#define _SWFDEC_AS_INTERPRET_H_
+
+#include <libswfdec/swfdec_as_types.h>
+
+G_BEGIN_DECLS
+
+/* defines minimum and maximum versions for which we have seperate scripts */
+#define SWFDEC_AS_MIN_SCRIPT_VERSION 3
+#define SWFDEC_AS_MAX_SCRIPT_VERSION 7
+#define SWFDEC_AS_EXTRACT_SCRIPT_VERSION(v) MIN ((v) - SWFDEC_AS_MIN_SCRIPT_VERSION, SWFDEC_AS_MAX_SCRIPT_VERSION - SWFDEC_AS_MIN_SCRIPT_VERSION)
+
+typedef void (* SwfdecActionExec) (SwfdecAsContext *cx, guint action, const guint8 *data, guint len);
+typedef struct {
+ const char * name; /* name identifying the action */
+ char * (* print) (guint action, const guint8 *data, guint len);
+ int remove; /* values removed from stack or -1 for dynamic */
+ int add; /* values added to the stack or -1 for dynamic */
+ SwfdecActionExec exec[SWFDEC_AS_MAX_SCRIPT_VERSION - SWFDEC_AS_MIN_SCRIPT_VERSION + 1];
+ /* array is for version 3, 4, 5, 6, 7+ */
+} SwfdecActionSpec;
+
+extern const SwfdecActionSpec swfdec_as_actions[256];
+
+G_END_DECLS
+#endif
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index a537953..293a48e 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -23,6 +23,7 @@
#include "swfdec_script.h"
#include "swfdec_as_context.h"
+#include "swfdec_as_interpret.h"
#include "swfdec_debug.h"
#include "swfdec_debugger.h"
@@ -148,2445 +149,10 @@ swfdec_script_add_to_player (SwfdecScrip
}
}
-#define swfdec_action_has_register(cx, i) \
- ((i) < ((SwfdecScript *) (cx)->fp->swf)->n_registers)
-
-#if 0
-static SwfdecMovie *
-swfdec_action_get_target (JSContext *cx)
-{
- JSObject *object = cx->fp->scopeChain;
- /* this whole function needs a big FIXME */
- if (JS_GetClass (object) == &js_WithClass)
- object = JS_GetPrototype (cx, object);
- return swfdec_scriptable_from_jsval (cx, OBJECT_TO_JSVAL (object), SWFDEC_TYPE_MOVIE);
-}
-
-static JSBool
-swfdec_action_push_string (JSContext *cx, const char *s)
-{
- JSString *string = JS_NewStringCopyZ (cx, s);
- if (string == NULL)
- return JS_FALSE;
- *cx->fp->sp++ = STRING_TO_JSVAL (string);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_value_to_boolean_5 (JSContext *cx, jsval val)
-{
- if (JSVAL_IS_BOOLEAN (val)) {
- return JSVAL_TO_BOOLEAN (val);
- } else if (JSVAL_IS_INT (val)) {
- return JSVAL_TO_INT (val) != 0;
- } else if (JSVAL_IS_DOUBLE (val)) {
- double d = *JSVAL_TO_DOUBLE (val);
- return d != 0.0 && !isnan (d);
- } else if (JSVAL_IS_STRING (val)) {
- double d;
- if (!JS_ValueToNumber (cx, val, &d))
- return 0;
- return d != 0.0 && !isnan (d);
- } else if (JSVAL_IS_NULL (val)) {
- return JS_FALSE;
- } else if (JSVAL_IS_VOID (val)) {
- return JS_FALSE;
- } else if (JSVAL_IS_OBJECT (val)) {
- return JS_TRUE;
- }
- g_assert_not_reached ();
- return JS_FALSE;
-}
-
-static JSBool
-swfdec_value_to_boolean_7 (JSContext *cx, jsval val)
-{
- if (JSVAL_IS_BOOLEAN (val)) {
- return JSVAL_TO_BOOLEAN (val);
- } else if (JSVAL_IS_INT (val)) {
- return JSVAL_TO_INT (val) != 0;
- } else if (JSVAL_IS_DOUBLE (val)) {
- double d = *JSVAL_TO_DOUBLE (val);
- return d != 0.0 && !isnan (d);
- } else if (JSVAL_IS_STRING (val)) {
- return JS_GetStringLength (JSVAL_TO_STRING (val)) > 0;
- } else if (JSVAL_IS_NULL (val)) {
- return JS_FALSE;
- } else if (JSVAL_IS_VOID (val)) {
- return JS_FALSE;
- } else if (JSVAL_IS_OBJECT (val)) {
- return JS_TRUE;
- }
- g_assert_not_reached ();
- return JS_FALSE;
-}
-
-static double
-swfdec_value_to_number (JSContext *cx, jsval val)
-{
- if (JSVAL_IS_INT (val)) {
- return JSVAL_TO_INT (val);
- } else if (JSVAL_IS_DOUBLE (val)) {
- return *JSVAL_TO_DOUBLE (val);
- } else if (JSVAL_IS_BOOLEAN (val)) {
- return JSVAL_TO_BOOLEAN (val);
- } else if (JSVAL_IS_STRING (val)) {
- double d;
- if (!JS_ValueToNumber (cx, val, &d))
- return 0;
- return d;
- } else if (JSVAL_IS_OBJECT(val) && (((SwfdecScript *) cx->fp->swf)->version >= 6)) {
- /* Checking for version 6 is completely wrong, but a lot of the testsuite
- * depends on it (oops).
- * The code calls the valueOf function and returns 0 if no such function exists.
- */
- return JSVAL_IS_NULL (val) ? 0 : *cx->runtime->jsNaN;
- } else {
- return 0;
- }
-}
-
-static JSBool
-swfdec_value_to_number_7 (JSContext *cx, jsval val, double *d)
-{
- if (JSVAL_IS_OBJECT (val)) {
- *d = *cx->runtime->jsNaN;
- return JS_TRUE;
- } else if (JSVAL_IS_STRING (val) &&
- JS_GetStringLength (JSVAL_TO_STRING (val)) == 0) {
- *d = *cx->runtime->jsNaN;
- return JS_TRUE;
- } else {
- return JS_ValueToNumber (cx, val, d);
- }
-}
-
-/*** ALL THE ACTION IS HERE ***/
-
-static JSBool
-swfdec_action_stop (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
- if (movie)
- movie->stopped = TRUE;
- else
- SWFDEC_ERROR ("no movie to stop");
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_play (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
- if (movie)
- movie->stopped = FALSE;
- else
- SWFDEC_ERROR ("no movie to play");
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_next_frame (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
- if (movie) {
- if (movie->frame + 1 < movie->n_frames) {
- swfdec_movie_goto (movie, movie->frame + 1);
- } else {
- SWFDEC_INFO ("can't execute nextFrame, already at last frame");
- }
- } else {
- SWFDEC_ERROR ("no movie to nextFrame on");
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_previous_frame (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
- if (movie) {
- if (movie->frame > 0) {
- swfdec_movie_goto (movie, movie->frame - 1);
- } else {
- SWFDEC_INFO ("can't execute previousFrame, already at first frame");
- }
- } else {
- SWFDEC_ERROR ("no movie to previousFrame on");
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_goto_frame (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
- guint frame;
-
- if (len != 2) {
- SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len);
- return JS_FALSE;
- }
- frame = GUINT16_FROM_LE (*((guint16 *) data));
- if (movie) {
- swfdec_movie_goto (movie, frame);
- movie->stopped = TRUE;
- } else {
- SWFDEC_ERROR ("no movie to goto on");
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_goto_label (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
-
- if (!memchr (data, 0, len)) {
- SWFDEC_ERROR ("GotoLabel action does not specify a string");
- return JS_FALSE;
- }
-
- if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
- int frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, (const char *) data);
- if (frame == -1)
- return JS_TRUE;
- swfdec_movie_goto (movie, frame);
- movie->stopped = TRUE;
- } else {
- SWFDEC_ERROR ("no movie to goto on");
- }
- return JS_TRUE;
-}
-
-static int
-swfdec_value_to_frame (JSContext *cx, SwfdecMovie *movie, jsval val)
-{
- int frame;
-
- if (JSVAL_IS_STRING (val)) {
- const char *name = swfdec_js_to_string (cx, val);
- char *end;
- if (name == NULL ||
- !SWFDEC_IS_SPRITE_MOVIE (movie))
- return -1;
- if (strchr (name, ':')) {
- SWFDEC_ERROR ("FIXME: handle targets");
- }
- /* treat valid encoded numbers as numbers, otherwise assume it's a frame label */
- frame = strtol (name, &end, 0);
- if (*end != '\0')
- frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name);
- else
- frame--;
- } else if (JSVAL_IS_INT (val)) {
- return JSVAL_TO_INT (val) - 1;
- } else if (JSVAL_IS_DOUBLE (val)) {
- return (int) *JSVAL_TO_DOUBLE (val) - 1;
- } else {
- /* FIXME: how do we treat undefined etc? */
- frame = -1;
- }
- return frame;
-}
-
-static JSBool
-swfdec_action_goto_frame2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecBits bits;
- guint bias;
- gboolean play;
- jsval val;
- SwfdecMovie *movie;
-
- swfdec_bits_init_data (&bits, data, len);
- if (swfdec_bits_getbits (&bits, 6)) {
- SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
- }
- bias = swfdec_bits_getbit (&bits);
- play = swfdec_bits_getbit (&bits);
- if (bias) {
- bias = swfdec_bits_get_u16 (&bits);
- }
- val = cx->fp->sp[-1];
- cx->fp->sp--;
- movie = swfdec_action_get_target (cx);
- /* now set it */
- if (movie) {
- int frame = swfdec_value_to_frame (cx, movie, val);
- if (frame < 0)
- return JS_TRUE;
- frame += bias;
- frame = CLAMP (frame, 0, (int) movie->n_frames - 1);
- swfdec_movie_goto (movie, frame);
- movie->stopped = !play;
- } else {
- SWFDEC_ERROR ("no movie to GotoFrame2 on");
- }
- return JS_TRUE;
-}
-
-static void
-swfdec_script_skip_actions (JSContext *cx, guint jump)
-{
- SwfdecScript *script = cx->fp->swf;
- guint8 *pc = cx->fp->pc;
- guint8 *endpc = script->buffer->data + script->buffer->length;
-
- /* jump instructions */
- g_assert (script);
- do {
- if (pc >= endpc)
- break;
- if (*pc & 0x80) {
- if (pc + 2 >= endpc)
- break;
- pc += 3 + GUINT16_FROM_LE (*((guint16 *) (pc + 1)));
- } else {
- pc++;
- }
- } while (jump-- > 0);
- cx->fp->pc = pc;
-}
-
-static JSBool
-swfdec_action_wait_for_frame2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval val;
- SwfdecMovie *movie;
-
- if (len != 1) {
- SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
- return JS_FALSE;
- }
- val = cx->fp->sp[-1];
- cx->fp->sp--;
- movie = swfdec_action_get_target (cx);
- if (movie) {
- int frame = swfdec_value_to_frame (cx, movie, val);
- guint jump = data[2];
- guint loaded;
- if (frame < 0)
- return JS_TRUE;
- if (SWFDEC_IS_ROOT_MOVIE (movie)) {
- SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie)->decoder;
- loaded = dec->frames_loaded;
- g_assert (loaded <= movie->n_frames);
- } else {
- loaded = movie->n_frames;
- }
- if (loaded < (guint) frame)
- swfdec_script_skip_actions (cx, jump);
- } else {
- SWFDEC_ERROR ("no movie to WaitForFrame2 on");
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_wait_for_frame (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_action_get_target (cx);
- guint frame, jump, loaded;
-
- if (len != 3) {
- SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len);
- return JS_TRUE;
- }
- if (movie == NULL) {
- SWFDEC_ERROR ("no movie for WaitForFrame");
- return JS_TRUE;
- }
-
- frame = GUINT16_FROM_LE (*((guint16 *) data));
- jump = data[2];
- if (SWFDEC_IS_ROOT_MOVIE (movie)) {
- SwfdecDecoder *dec = SWFDEC_ROOT_MOVIE (movie)->decoder;
- loaded = dec->frames_loaded;
- g_assert (loaded <= movie->n_frames);
- } else {
- loaded = movie->n_frames;
- }
- if (loaded < frame)
- swfdec_script_skip_actions (cx, jump);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_constant_pool (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecConstantPool *pool;
-
- pool = swfdec_constant_pool_new_from_action (data, len);
- if (pool == NULL)
- return JS_FALSE;
- if (cx->fp->constant_pool)
- swfdec_constant_pool_free (cx->fp->constant_pool);
- cx->fp->constant_pool = pool;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_push (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- /* FIXME: supply API for this */
- SwfdecBits bits;
- guint stackspace = cx->fp->spend - cx->fp->sp;
-
- swfdec_bits_init_data (&bits, data, len);
- while (swfdec_bits_left (&bits) && stackspace-- > 0) {
- guint type = swfdec_bits_get_u8 (&bits);
- SWFDEC_LOG ("push type %u", type);
- switch (type) {
- case 0: /* string */
- {
- const char *s = swfdec_bits_skip_string (&bits);
- if (!swfdec_action_push_string (cx, s))
- return JS_FALSE;
- break;
- }
- case 1: /* float */
- {
- double d = swfdec_bits_get_float (&bits);
- if (!JS_NewDoubleValue (cx, d, cx->fp->sp))
- return JS_FALSE;
- cx->fp->sp++;
- break;
- }
- case 2: /* null */
- *cx->fp->sp++ = JSVAL_NULL;
- break;
- case 3: /* undefined */
- *cx->fp->sp++ = JSVAL_VOID;
- break;
- case 4: /* register */
- {
- guint regnum = swfdec_bits_get_u8 (&bits);
- if (!swfdec_action_has_register (cx, regnum)) {
- SWFDEC_ERROR ("cannot Push register %u: not enough registers", regnum);
- return JS_FALSE;
- }
- *cx->fp->sp++ = cx->fp->vars[regnum];
- break;
- }
- case 5: /* boolean */
- *cx->fp->sp++ = swfdec_bits_get_u8 (&bits) ? JSVAL_TRUE : JSVAL_FALSE;
- break;
- case 6: /* double */
- {
- double d = swfdec_bits_get_double (&bits);
- if (!JS_NewDoubleValue (cx, d, cx->fp->sp))
- return JS_FALSE;
- cx->fp->sp++;
- break;
- }
- case 7: /* 32bit int */
- {
- int i = swfdec_bits_get_u32 (&bits);
- *cx->fp->sp++ = INT_TO_JSVAL (i);
- break;
- }
- case 8: /* 8bit ConstantPool address */
- {
- guint i = swfdec_bits_get_u8 (&bits);
- SwfdecConstantPool *pool = cx->fp->constant_pool;
- if (pool == NULL) {
- SWFDEC_ERROR ("no constant pool to push from");
- return JS_FALSE;
- }
- if (i >= swfdec_constant_pool_size (pool)) {
- SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
- i, swfdec_constant_pool_size (pool));
- return JS_FALSE;
- }
- if (!swfdec_action_push_string (cx, swfdec_constant_pool_get (pool, i)))
- return JS_FALSE;
- break;
- }
- case 9: /* 16bit ConstantPool address */
- {
- guint i = swfdec_bits_get_u16 (&bits);
- SwfdecConstantPool *pool = cx->fp->constant_pool;
- if (pool == NULL) {
- SWFDEC_ERROR ("no constant pool to push from");
- return JS_FALSE;
- }
- if (i >= swfdec_constant_pool_size (pool)) {
- SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
- i, swfdec_constant_pool_size (pool));
- return JS_FALSE;
- }
- if (!swfdec_action_push_string (cx, swfdec_constant_pool_get (pool, i)))
- return JS_FALSE;
- break;
- }
- default:
- SWFDEC_ERROR ("Push: type %u not implemented", type);
- return JS_FALSE;
- }
- }
- return swfdec_bits_left (&bits) ? JS_FALSE : JS_TRUE;
-}
-
-static JSBool
-swfdec_action_get_variable (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *s;
-
- s = swfdec_js_to_string (cx, cx->fp->sp[-1]);
- if (s == NULL)
- return JS_FALSE;
- cx->fp->sp[-1] = swfdec_js_eval (cx, NULL, s);
-#ifdef SWFDEC_WARN_MISSING_PROPERTIES
- if (cx->fp->sp[-1] == JSVAL_VOID) {
- SWFDEC_WARNING ("no variable named %s", s);
- }
-#endif
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_set_variable (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *s;
-
- s = swfdec_js_to_string (cx, cx->fp->sp[-2]);
- if (s == NULL)
- return JS_FALSE;
-
- swfdec_js_eval_set (cx, NULL, s, cx->fp->sp[-1]);
- cx->fp->sp -= 2;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_trace (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecPlayer *player = JS_GetContextPrivate (cx);
- const char *bytes;
-
- bytes = swfdec_js_to_string (cx, cx->fp->sp[-1]);
- cx->fp->sp--;
- if (bytes == NULL)
- return JS_TRUE;
-
- swfdec_player_trace (player, bytes);
- return JS_TRUE;
-}
-
-/**
- * swfdec_action_invoke:
- * @cx: the #JSContext
- * @n_args: number of arguments
- *
- * This function is similar to js_Invoke, however it uses a reversed stack
- * order. sp[-1] has to be the function to call, sp[-2] will be the object the
- * function is called on, sp[-3] is the first argument, followed by the rest of
- * the arguments. The function removes all of these argumends from the stack
- * and pushes the return value on top.
- *
- * Returns: JS_TRUE on success, JS_FALSE on failure.
- **/
-static JSBool
-swfdec_action_call (JSContext *cx, guint n_args, guint flags)
-{
- JSStackFrame *fp = cx->fp;
- int i, j;
- jsval tmp;
- guint stacksize;
-
- stacksize = fp->sp - fp->spbase;
- g_assert (stacksize >= 2);
- if (n_args + 2 > stacksize) {
- SWFDEC_WARNING ("broken script. Want %u arguments, only got %u", n_args, stacksize - 2);
- n_args = stacksize - 2;
- if (!swfdec_script_ensure_stack (cx, n_args + 2))
- return JS_FALSE;
- }
-
- j = -1;
- i = - (n_args + 2);
- while (i < j) {
- tmp = fp->sp[j];
- fp->sp[j] = fp->sp[i];
- fp->sp[i] = tmp;
- j--;
- i++;
- }
- return js_Invoke (cx, n_args, flags);
-}
-
-/* FIXME: lots of overlap with swfdec_action_call_method */
-static JSBool
-swfdec_action_call_function (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- const char *s;
- guint32 n_args;
- JSObject *obj, *pobj;
- JSProperty *prop;
- jsval fun;
- JSAtom *atom;
-
- if (!swfdec_script_ensure_stack (cx, 2))
- return JS_FALSE;
- s = swfdec_js_to_string (cx, fp->sp[-1]);
- if (s == NULL)
- return JS_FALSE;
- if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args))
- return JS_FALSE;
-
- if (!(atom = js_Atomize (cx, s, strlen (s), 0)) ||
- !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop))
- return JS_FALSE;
- if (!JS_GetProperty (cx, obj, s, &fun))
- return JS_FALSE;
- if (!JSVAL_IS_OBJECT (fun)) {
- /* FIXME: figure out what class we operate on */
- SWFDEC_WARNING ("%s is not a function", s);
- }
- fp->sp[-1] = fun;
- fp->sp[-2] = OBJECT_TO_JSVAL (obj);
- swfdec_action_call (cx, n_args, 0);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_call_method (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- const char *s;
- guint32 n_args;
- JSObject *obj;
- jsval fun;
-
- if (!swfdec_script_ensure_stack (cx, 3))
- return JS_FALSE;
- if (fp->sp[-1] == JSVAL_VOID) {
- s = "";
- } else {
- s = swfdec_js_to_string (cx, fp->sp[-1]);
- if (s == NULL)
- return JS_FALSE;
- }
- if (!JS_ValueToECMAUint32 (cx, fp->sp[-3], &n_args))
- return JS_FALSE;
-
- if (!JS_ValueToObject (cx, fp->sp[-2], &obj))
- return JS_FALSE;
- if (obj == NULL)
- goto fail;
- if (s[0] == '\0') {
- fun = OBJECT_TO_JSVAL (obj);
- } else {
- if (!JS_GetProperty (cx, obj, s, &fun))
- return JS_FALSE;
- if (!JSVAL_IS_OBJECT (fun)) {
- SWFDEC_WARNING ("%s:%s is not a function", JS_GetClass (obj)->name, s);
- }
- }
- fp->sp--;
- fp->sp[-1] = fun;
- fp->sp[-2] = OBJECT_TO_JSVAL (obj);
- swfdec_action_call (cx, n_args, 0);
- return JS_TRUE;
-
-fail:
- fp->sp -= 2 + n_args;
- fp->sp[-1] = JSVAL_VOID;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_pop (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- cx->fp->sp--;
- return JS_TRUE;
-}
-
-static const char *
-swfdec_eval_jsval (JSContext *cx, JSObject *obj, jsval *val)
-{
- if (JSVAL_IS_STRING (*val)) {
- const char *bytes = swfdec_js_to_string (cx, *val);
- if (bytes == NULL)
- return NULL;
- *val = swfdec_js_eval (cx, obj, bytes);
- return bytes;
- } else {
- if (obj == NULL) {
- obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain);
- }
- *val = OBJECT_TO_JSVAL (obj);
- return ".";
- }
-}
-
-static const char *properties[22] = {
- "_x", "_y", "_xscale", "_yscale", "_currentframe",
- "_totalframes", "_alpha", "_visible", "_width", "_height",
- "_rotation", "_target", "_framesloaded", "_name", "_droptarget",
- "_url", "_highquality", "_focusrect", "_soundbuftime", "_quality",
- "_xmouse", "_ymouse"
-};
-
-static JSBool
-swfdec_action_get_property (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval val;
- SwfdecMovie *movie;
- JSObject *jsobj;
- guint32 id;
- const char *bytes;
-
- if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &id))
- return JS_FALSE;
- val = cx->fp->sp[-2];
- bytes = swfdec_eval_jsval (cx, NULL, &val);
- if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) {
- SWFDEC_WARNING ("trying to SetProperty %u, not allowed", id);
- goto out;
- }
-
- if (bytes == NULL)
- return JS_FALSE;
- if (*bytes == '\0') {
- JSObject *pobj;
- JSProperty *prop;
- JSAtom *atom = js_Atomize (cx, properties[id], strlen (properties[id]), 0);
- if (atom == NULL)
- return JS_FALSE;
- if (!js_FindProperty (cx, (jsid) atom, &jsobj, &pobj, &prop))
- return JS_FALSE;
- if (!prop)
- return JS_FALSE;
- if (!OBJ_GET_PROPERTY (cx, jsobj, (jsid) prop->id, &val))
- return JS_FALSE;
- } else {
- movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE);
- if (movie == NULL) {
- SWFDEC_WARNING ("specified target does not reference a movie clip");
- goto out;
- }
-
- jsobj = JSVAL_TO_OBJECT (val);
- val = JSVAL_VOID;
-
- if (!JS_GetProperty (cx, jsobj, properties[id], &val))
- return JS_FALSE;
- }
-
-out:
- cx->fp->sp -= 1;
- cx->fp->sp[-1] = val;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_set_property (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval val;
- SwfdecMovie *movie;
- JSObject *jsobj;
- guint32 id;
- const char *bytes;
-
- val = cx->fp->sp[-3];
- if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &id))
- return JS_FALSE;
- bytes = swfdec_eval_jsval (cx, NULL, &val);
- if (!bytes)
- return JS_FALSE;
- if (id > (((SwfdecScript *) cx->fp->swf)->version > 4 ? 21 : 18)) {
- SWFDEC_WARNING ("trying to SetProperty %u, not allowed", id);
- goto out;
- }
- if (*bytes == '\0' || *bytes == '.')
- val = OBJECT_TO_JSVAL (cx->fp->varobj);
- movie = swfdec_scriptable_from_jsval (cx, val, SWFDEC_TYPE_MOVIE);
- if (movie == NULL) {
- SWFDEC_WARNING ("specified target does not reference a movie clip");
- goto out;
- }
- jsobj = JSVAL_TO_OBJECT (val);
-
- if (!JS_SetProperty (cx, jsobj, properties[id], &cx->fp->sp[-1]))
- return JS_FALSE;
-
-out:
- cx->fp->sp -= 3;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_binary (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval lval, rval;
- double l, r;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- if (((SwfdecScript *) cx->fp->swf)->version < 7) {
- l = swfdec_value_to_number (cx, lval);
- r = swfdec_value_to_number (cx, rval);
- } else {
- if (!swfdec_value_to_number_7 (cx, lval, &l) ||
- !swfdec_value_to_number_7 (cx, rval, &r))
- return JS_FALSE;
- }
- cx->fp->sp--;
- switch (action) {
- case 0x0a:
- l = l + r;
- break;
- case 0x0b:
- l = l - r;
- break;
- case 0x0c:
- l = l * r;
- break;
- case 0x0d:
- if (((SwfdecScript *) cx->fp->swf)->version < 5) {
- if (r == 0) {
- JSString *str = JS_InternString (cx, "#ERROR#");
- if (str == NULL)
- return JS_FALSE;
- cx->fp->sp[-1] = STRING_TO_JSVAL (str);
- return JS_TRUE;
- }
- } else if (((SwfdecScript *) cx->fp->swf)->version < 7) {
- if (isnan (r))
- r = 0;
- }
- l = l / r;
- break;
- default:
- g_assert_not_reached ();
- return r;
- }
- return JS_NewNumberValue (cx, l, &cx->fp->sp[-1]);
-}
-
-static JSString *
-swfdec_action_to_string_5 (JSContext *cx, jsval val)
-{
- if (JSVAL_IS_VOID (val))
- return cx->runtime->emptyString;
- return js_ValueToString (cx, val);
-}
-
-static JSBool
-swfdec_action_add2_5 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval rval, lval;
- gboolean cond;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) {
- JSString *str, *str2;
- if (cond) {
- str = JSVAL_TO_STRING (lval);
- if ((str2 = swfdec_action_to_string_5 (cx, rval)) == NULL)
- return JS_FALSE;
- } else {
- str2 = JSVAL_TO_STRING (rval);
- if ((str = swfdec_action_to_string_5 (cx, lval)) == NULL)
- return JS_FALSE;
- }
- str = js_ConcatStrings (cx, str, str2);
- if (!str)
- return JS_FALSE;
- cx->fp->sp--;
- cx->fp->sp[-1] = STRING_TO_JSVAL (str);
- } else {
- double d, d2;
- d = swfdec_value_to_number (cx, lval);
- d2 = swfdec_value_to_number (cx, rval);
- d += d2;
- cx->fp->sp--;
- return JS_NewNumberValue(cx, d, &cx->fp->sp[-1]);
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_add2_7 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval rval, lval;
- gboolean cond;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- if ((cond = JSVAL_IS_STRING (lval)) || JSVAL_IS_STRING (rval)) {
- JSString *str, *str2;
- if (cond) {
- str = JSVAL_TO_STRING (lval);
- if ((str2 = js_ValueToString (cx, rval)) == NULL)
- return JS_FALSE;
- } else {
- str2 = JSVAL_TO_STRING (rval);
- if ((str = js_ValueToString (cx, lval)) == NULL)
- return JS_FALSE;
- }
- str = js_ConcatStrings (cx, str, str2);
- if (!str)
- return JS_FALSE;
- cx->fp->sp--;
- cx->fp->sp[-1] = STRING_TO_JSVAL (str);
- } else {
- double d, d2;
- if (!swfdec_value_to_number_7 (cx, lval, &d) ||
- !swfdec_value_to_number_7 (cx, rval, &d2))
- return JS_FALSE;
- d += d2;
- cx->fp->sp--;
- return JS_NewNumberValue(cx, d, &cx->fp->sp[-1]);
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_get_member (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *s;
- jsval o;
-
- s = swfdec_js_to_string (cx, cx->fp->sp[-1]);
- if (s == NULL)
- return JS_FALSE;
-
- o = cx->fp->sp[-2];
- if (JSVAL_IS_OBJECT (o) && !JSVAL_IS_NULL (o)) {
- if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (o), s, &cx->fp->sp[-2]))
- return JS_FALSE;
-#ifdef SWFDEC_WARN_MISSING_PROPERTIES
- if (cx->fp->sp[-2] == JSVAL_VOID) {
- const JSClass *clasp = JS_GetClass (JSVAL_TO_OBJECT (o));
- if (clasp != &js_ObjectClass) {
- SWFDEC_WARNING ("no variable named %s:%s", clasp->name, s);
- }
- }
-#endif
- } else {
- cx->fp->sp[-2] = JSVAL_VOID;
- }
- cx->fp->sp--;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_set_member (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *s;
-
- s = swfdec_js_to_string (cx, cx->fp->sp[-2]);
- if (s == NULL)
- return JS_FALSE;
-
- if (JSVAL_IS_OBJECT (cx->fp->sp[-3]) && !JSVAL_IS_NULL (cx->fp->sp[-3])) {
- if (!JS_SetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-3]), s, &cx->fp->sp[-1]))
- return JS_FALSE;
- }
- cx->fp->sp -= 3;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_new_comparison_6 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval lval, rval;
- double d, d2;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- cx->fp->sp--;
- d = swfdec_value_to_number (cx, lval);
- d2 = swfdec_value_to_number (cx, rval);
- if (action == 0x48)
- cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (d < d2);
- else
- cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (d > d2);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_new_comparison_7 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval lval, rval;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- cx->fp->sp--;
- if (JSVAL_IS_VOID (rval) || JSVAL_IS_VOID (lval)) {
- cx->fp->sp[-1] = JSVAL_VOID;
- } else if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) {
- int comp = JS_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval));
- cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (action == 0x48 ? comp < 0 : comp > 0);
- } else {
- double d, d2;
- if (!JS_ValueToNumber(cx, lval, &d) ||
- !JS_ValueToNumber(cx, rval, &d2))
- return JS_FALSE;
- cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (action == 0x48 ? d < d2 : d > d2);
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_not_4 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d;
-
- d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
- cx->fp->sp[-1] = INT_TO_JSVAL (d == 0 ? 1 : 0);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_not_5 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d;
-
- d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
- cx->fp->sp[-1] = d == 0 ? JSVAL_TRUE : JSVAL_FALSE;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_jump (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- if (len != 2) {
- SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
- return JS_FALSE;
- }
- cx->fp->pc += 5 + GINT16_FROM_LE (*((gint16*) data));
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_if (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d;
-
- if (len != 2) {
- SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
- return JS_FALSE;
- }
- d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
- cx->fp->sp--;
- if (d != 0)
- cx->fp->pc += 5 + GINT16_FROM_LE (*((gint16*) data));
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_decrement (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d;
-
- d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
- d--;
- return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_increment (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d;
-
- d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
- d++;
- return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_get_url (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie;
- SwfdecBits bits;
- const char *url, *target;
-
- swfdec_bits_init_data (&bits, data, len);
- url = swfdec_bits_skip_string (&bits);
- target = swfdec_bits_skip_string (&bits);
- if (swfdec_bits_left (&bits)) {
- SWFDEC_WARNING ("leftover bytes in GetURL action");
- }
- movie = swfdec_action_get_target (cx);
- if (movie)
- swfdec_root_movie_load (SWFDEC_ROOT_MOVIE (movie->root), url, target);
- else
- SWFDEC_WARNING ("no movie to load");
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_get_url2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *target, *url;
- guint method;
- SwfdecMovie *movie;
-
- if (len != 1) {
- SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len);
- return JS_FALSE;
- }
- target = swfdec_js_to_string (cx, cx->fp->sp[-1]);
- url = swfdec_js_to_string (cx, cx->fp->sp[-2]);
- if (target == NULL || url == NULL)
- return JS_FALSE;
- method = data[0] >> 6;
- if (method == 3) {
- SWFDEC_ERROR ("GetURL method 3 invalid");
- method = 0;
- }
- if (method) {
- SWFDEC_ERROR ("FIXME: implement encoding variables using %s", method == 1 ? "GET" : "POST");
- }
- if (data[0] & 2) {
- SWFDEC_ERROR ("FIXME: implement LoadTarget");
- }
- if (data[0] & 1) {
- SWFDEC_ERROR ("FIXME: implement LoadVariables");
- }
- movie = swfdec_action_get_target (cx);
- if (movie)
- swfdec_root_movie_load (SWFDEC_ROOT_MOVIE (movie->root), url, target);
- else
- SWFDEC_WARNING ("no movie to load");
- cx->fp->sp -= 2;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_string_add (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSString *lval, *rval;
-
- rval = JS_ValueToString (cx, cx->fp->sp[-1]);
- lval = JS_ValueToString (cx, cx->fp->sp[-2]);
- if (lval == NULL || rval == NULL)
- return FALSE;
- lval = JS_ConcatStrings (cx, lval, rval);
- if (lval == NULL)
- return FALSE;
- cx->fp->sp--;
- cx->fp->sp[-1] = STRING_TO_JSVAL (lval);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_push_duplicate (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- cx->fp->sp++;
- cx->fp->sp[-1] = cx->fp->sp[-2];
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_random_number (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- gint32 max, result;
-
- if (!JS_ValueToECMAInt32 (cx, cx->fp->sp[-1], &max))
- return JS_FALSE;
-
- if (max <= 0)
- result = 0;
- else
- result = g_random_int_range (0, max);
-
- return JS_NewNumberValue(cx, result, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_old_compare (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval rval, lval;
- double l, r;
- JSBool cond;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- l = swfdec_value_to_number (cx, lval);
- r = swfdec_value_to_number (cx, rval);
- switch (action) {
- case 0x0e:
- cond = l == r;
- break;
- case 0x0f:
- cond = l < r;
- break;
- default:
- g_assert_not_reached ();
- return JS_FALSE;
- }
- cx->fp->sp--;
- if (((SwfdecScript *) cx->fp->swf)->version < 5) {
- cx->fp->sp[-1] = INT_TO_JSVAL (cond ? 1 : 0);
- } else {
- cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (cond);
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_equals2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval rval, lval;
- int ltag, rtag;
- JSBool cond;
-
- rval = cx->fp->sp[-1];
- lval = cx->fp->sp[-2];
- ltag = JSVAL_TAG(lval);
- rtag = JSVAL_TAG(rval);
- if (ltag == rtag) {
- if (ltag == JSVAL_STRING) {
- cond = js_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)) == 0;
- } else if (ltag == JSVAL_DOUBLE) {
- cond = *JSVAL_TO_DOUBLE(lval) == *JSVAL_TO_DOUBLE(rval);
- } else {
- cond = lval == rval;
- }
- } else {
- if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) {
- cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval));
- } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) {
- cond = JS_FALSE;
- } else {
- if (ltag == JSVAL_OBJECT) {
- if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT(lval), 0, &lval))
- return JS_FALSE;
- ltag = JSVAL_TAG(lval);
- } else if (rtag == JSVAL_OBJECT) {
- if (!OBJ_DEFAULT_VALUE (cx, JSVAL_TO_OBJECT(rval), 0, &rval))
- return JS_FALSE;
- rtag = JSVAL_TAG(rval);
- }
- if (ltag == JSVAL_STRING && rtag == JSVAL_STRING) {
- cond = js_CompareStrings (JSVAL_TO_STRING (lval), JSVAL_TO_STRING (rval)) == 0;
- } else {
- double d, d2;
- if (!JS_ValueToNumber (cx, lval, &d) ||
- !JS_ValueToNumber (cx, rval, &d2))
- return JS_FALSE;
- cond = d == d2;
- }
- }
- }
- cx->fp->sp--;
- cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (cond);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_do_set_target (JSContext *cx, JSObject *target)
-{
- JSObject *with;
-
- /* FIXME: this whole function stops working the moment it's used together
- * with With */
- with = js_NewObject(cx, &js_WithClass, target, cx->fp->scopeChain);
- if (!with)
- return JS_FALSE;
- cx->fp->scopeChain = with;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_do_unset_target (JSContext *cx)
-{
- if (JS_GetClass (cx->fp->scopeChain) != &js_WithClass) {
- SWFDEC_ERROR ("Cannot unset target: scope chain contains no with object");
- return JS_TRUE;
- }
- cx->fp->scopeChain = JS_GetParent (cx, cx->fp->scopeChain);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_set_target (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval target;
-
- if (!memchr (data, 0, len)) {
- SWFDEC_ERROR ("SetTarget action does not specify a string");
- return JS_FALSE;
- }
- if (*data == '\0')
- return swfdec_action_do_unset_target (cx);
- target = swfdec_js_eval (cx, NULL, (const char *) data);
- if (!JSVAL_IS_OBJECT (target) || JSVAL_IS_NULL (target)) {
- SWFDEC_WARNING ("target is not an object");
- return JS_TRUE;
- }
- return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (target));
-}
-
-static JSBool
-swfdec_action_set_target2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval val;
-
- val = cx->fp->sp[-1];
- cx->fp->sp--;
- if (!JSVAL_IS_OBJECT (val) || JSVAL_IS_NULL (val)) {
- SWFDEC_WARNING ("target is not an object");
- return JS_TRUE;
- }
- return swfdec_action_do_set_target (cx, JSVAL_TO_OBJECT (val));
-}
-
-static JSBool
-swfdec_action_start_drag (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- guint n_args = 1;
-
- if (!swfdec_script_ensure_stack (cx, 3))
- return JS_FALSE;
- if (!swfdec_eval_jsval (cx, NULL, &fp->sp[-1]))
- return JS_FALSE;
- if (swfdec_value_to_number (cx, fp->sp[-3])) {
- jsval tmp;
- if (!swfdec_script_ensure_stack (cx, 7))
- return JS_FALSE;
- n_args = 5;
- /* yay for order */
- tmp = fp->sp[-4];
- fp->sp[-4] = fp->sp[-7];
- fp->sp[-7] = tmp;
- tmp = fp->sp[-6];
- fp->sp[-6] = fp->sp[-5];
- fp->sp[-5] = tmp;
- }
- if (!JSVAL_IS_OBJECT (fp->sp[-1]) || JSVAL_IS_NULL (fp->sp[-1])) {
- fp->sp -= n_args + 2;
- return JS_TRUE;
- }
- fp->sp[-3] = fp->sp[-2];
- fp->sp[-2] = fp->sp[-1];
- if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (fp->sp[-2]), "startDrag", &fp->sp[-1]))
- return JS_FALSE;
- swfdec_action_call (cx, n_args, 0);
- fp->sp--;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_end_drag (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecPlayer *player = JS_GetContextPrivate (cx);
- swfdec_player_set_drag_movie (player, NULL, FALSE, NULL);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_stop_sounds (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecPlayer *player = JS_GetContextPrivate (cx);
-
- swfdec_player_stop_all_sounds (player);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_new_object (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- jsval constructor;
- JSObject *object;
- guint n_args;
- const char *name;
-
- if (!swfdec_script_ensure_stack (cx, 2))
- return JS_FALSE;
- constructor = fp->sp[-1];
- name = swfdec_eval_jsval (cx, NULL, &constructor);
- if (name == NULL)
- return JS_FALSE;
- if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args))
- return JS_FALSE;
- if (constructor == JSVAL_VOID) {
- SWFDEC_WARNING ("no constructor for %s", name);
- }
- fp->sp[-1] = constructor;
-
- if (!swfdec_js_construct_object (cx, NULL, constructor, &object))
- return JS_FALSE;
- if (object == NULL)
- goto fail;
- fp->sp[-2] = OBJECT_TO_JSVAL (object);
- if (!swfdec_action_call (cx, n_args, JSINVOKE_CONSTRUCT))
- return JS_FALSE;
- fp->sp[-1] = OBJECT_TO_JSVAL (object);
- return JS_TRUE;
-
-fail:
- fp->sp -= n_args + 1;
- fp->sp[-1] = JSVAL_VOID;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_new_method (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- const char *s;
- guint32 n_args;
- JSObject *object;
- jsval constructor;
-
- if (!swfdec_script_ensure_stack (cx, 3))
- return JS_FALSE;
- s = swfdec_js_to_string (cx, fp->sp[-1]);
- if (s == NULL)
- return JS_FALSE;
- if (!JS_ValueToECMAUint32 (cx, fp->sp[-3], &n_args))
- return JS_FALSE;
-
- if (!JS_ValueToObject (cx, fp->sp[-2], &object))
- return JS_FALSE;
- if (object == NULL)
- goto fail;
- if (s[0] == '\0') {
- constructor = OBJECT_TO_JSVAL (object);
- } else {
- if (!JS_GetProperty (cx, object, s, &constructor))
- return JS_FALSE;
- if (!JSVAL_IS_OBJECT (constructor)) {
- SWFDEC_WARNING ("%s:%s is not a function", JS_GetClass (object)->name, s);
- }
- }
- fp->sp[-1] = OBJECT_TO_JSVAL (constructor);
- if (!swfdec_js_construct_object (cx, NULL, constructor, &object))
- return JS_FALSE;
- if (object == NULL)
- goto fail;
- fp->sp[-2] = OBJECT_TO_JSVAL (object);
- if (!swfdec_action_call (cx, n_args, JSINVOKE_CONSTRUCT))
- return JS_FALSE;
- fp->sp[-1] = OBJECT_TO_JSVAL (object);
- return JS_TRUE;
-
-fail:
- fp->sp -= 2 + n_args;
- fp->sp[-1] = JSVAL_VOID;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_init_object (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- JSObject *object;
- guint n_args;
- gulong i;
-
- if (!JS_ValueToECMAUint32 (cx, fp->sp[-1], &n_args))
- return JS_FALSE;
- if (!swfdec_script_ensure_stack (cx, 2 * n_args + 1))
- return JS_FALSE;
-
- object = JS_NewObject (cx, &js_ObjectClass, NULL, NULL);
- if (object == NULL)
- return JS_FALSE;
- for (i = 0; i < n_args; i++) {
- const char *s = swfdec_js_to_string (cx, fp->sp[-3 - 2 * i]);
- if (s == NULL)
- return JS_FALSE;
- if (!JS_SetProperty (cx, object, s, &fp->sp[-2 - 2 * i]))
- return JS_FALSE;
- }
- fp->sp -= 2 * n_args;
- fp->sp[-1] = OBJECT_TO_JSVAL (object);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_init_array (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSStackFrame *fp = cx->fp;
- JSObject *array;
- int i, j;
- guint n_items;
-
- if (!JS_ValueToECMAUint32 (cx, fp->sp[-1], &n_items))
- return JS_FALSE;
- if (!swfdec_script_ensure_stack (cx, n_items + 1))
- return JS_FALSE;
-
- /* items are the wrong order on the stack */
- j = - 1 - n_items;
- for (i = - 2; i > j; i--, j++) {
- jsval tmp = fp->sp[i];
- fp->sp[i] = fp->sp[j];
- fp->sp[j] = tmp;
- }
- array = JS_NewArrayObject (cx, n_items, fp->sp - n_items - 1);
- if (array == NULL)
- return JS_FALSE;
- fp->sp -= n_items;
- fp->sp[-1] = OBJECT_TO_JSVAL (array);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_define_function (JSContext *cx, guint action,
- const guint8 *data, guint len)
-{
- const char *function_name;
- guint i, n_args, size;
- SwfdecBits bits;
- JSFunction *fun;
- SwfdecScript *script;
- JSObject *scope;
- gboolean has_preloads = FALSE;
- guint flags = 0;
- guint8 *preloads = NULL;
- gboolean v2 = (action == 0x8e);
-
- swfdec_bits_init_data (&bits, data, len);
- function_name = swfdec_bits_skip_string (&bits);
- if (function_name == NULL) {
- SWFDEC_ERROR ("could not parse function name");
- return JS_FALSE;
- }
- n_args = swfdec_bits_get_u16 (&bits);
- scope = cx->fp->scopeChain;
- script = cx->fp->swf;
- if (script->version == 5) {
- /* In Flash 5 there's only the root scope as a parent scope */
- JSObject *parent;
- /* FIXME: this implementation is hacky (but it works) */
- while (JS_GetClass (scope) == &js_CallClass && (parent = JS_GetParent (cx, scope)))
- scope = parent;
- }
- if (*function_name == '\0') {
- /* anonymous function */
- fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA | JSFUN_HEAVYWEIGHT,
- scope, NULL);
- } else {
- /* named function */
- fun = JS_NewFunction (cx, NULL, n_args, JSFUN_HEAVYWEIGHT,
- scope, function_name);
- }
- if (fun == NULL)
- return JS_FALSE;
- if (v2) {
- script->n_registers = swfdec_bits_get_u8 (&bits) + 1;
- flags = swfdec_bits_get_u16 (&bits);
- preloads = g_new0 (guint8, n_args);
- } else {
- script->n_registers = 5;
- }
- fun->nvars = script->n_registers;
- for (i = 0; i < n_args; i++) {
- JSAtom *atom;
- const char *arg_name;
- if (v2) {
- guint preload = swfdec_bits_get_u8 (&bits);
- if (preload && preload >= script->n_registers) {
- SWFDEC_ERROR ("argument %u is preloaded into register %u out of %u",
- i, preload, script->n_registers);
- return JS_FALSE;
- }
- if (preload != 0) {
- preloads[i] = preload;
- swfdec_bits_skip_string (&bits);
- has_preloads = TRUE;
- continue;
- }
- }
- arg_name = swfdec_bits_skip_string (&bits);
- if (arg_name == NULL || *arg_name == '\0') {
- SWFDEC_ERROR ("empty argument name not allowed");
- return JS_FALSE;
- }
- /* FIXME: check duplicate arguments */
- atom = js_Atomize (cx, arg_name, strlen (arg_name), 0);
- if (atom == NULL)
- return JS_FALSE;
- if (!js_AddNativeProperty (cx, fun->object, (jsid) atom,
- js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT,
- JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED,
- SPROP_HAS_SHORTID, i)) {
- return JS_FALSE;
- }
- }
- if (preloads && !has_preloads) {
- g_free (preloads);
- preloads = NULL;
- }
- size = swfdec_bits_get_u16 (&bits);
- /* check the script can be created */
- if (script->buffer->data + script->buffer->length < cx->fp->pc + 3 + len + size) {
- SWFDEC_ERROR ("size of function is too big");
- return FALSE;
- } else {
- /* create the script */
- const char *name = NULL;
- SwfdecBuffer *buffer = swfdec_buffer_new_subbuffer (script->buffer,
- cx->fp->pc + 3 + len - script->buffer->data, size);
- swfdec_bits_init (&bits, buffer);
- if (*function_name) {
- name = function_name;
- } else if (cx->fp->sp > cx->fp->spbase) {
- /* 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.
- */
- if (JSVAL_IS_STRING (cx->fp->sp[-1]))
- name = JS_GetStringBytes (JSVAL_TO_STRING (cx->fp->sp[-1]));
- }
- if (name == NULL)
- name = "unnamed_function";
- script = swfdec_script_new (&bits, name, ((SwfdecScript *) cx->fp->swf)->version);
- swfdec_buffer_unref (buffer);
- }
- if (script == NULL) {
- SWFDEC_ERROR ("failed to create script");
- g_free (preloads);
- return JS_FALSE;
- }
- if (cx->fp->constant_pool) {
- script->constant_pool = swfdec_constant_pool_get_area (cx->fp->swf,
- cx->fp->constant_pool);
- }
- script->flags = flags;
- script->preloads = preloads;
- fun->swf = script;
- swfdec_script_add_to_player (script, JS_GetContextPrivate (cx));
- /* attach the function */
- if (*function_name == '\0') {
- if (cx->fp->sp >= cx->fp->spend) {
- SWFDEC_ERROR ("not enough stack space available");
- return JS_FALSE;
- }
- *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object);
- } else {
- jsval val = OBJECT_TO_JSVAL (fun->object);
- if (!JS_SetProperty (cx, cx->fp->varobj, function_name, &val))
- return JS_FALSE;
- }
-
- /* update current context */
- cx->fp->pc += 3 + len + size;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_bitwise (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- guint32 a, b;
- double d;
-
- if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &a) ||
- !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &b))
- return JS_FALSE;
-
- switch (action) {
- case 0x60:
- d = (int) (a & b);
- break;
- case 0x61:
- d = (int) (a | b);
- break;
- case 0x62:
- d = (int) (a ^ b);
- break;
- default:
- g_assert_not_reached ();
- return JS_FALSE;
- }
-
- cx->fp->sp--;
- return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_shift (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- guint32 amount, value;
- double d;
-
- if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &amount) ||
- !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &value))
- return JS_FALSE;
-
- amount &= 31;
- switch (action) {
- case 0x63:
- d = value << amount;
- break;
- case 0x64:
- d = ((gint) value) >> amount;
- break;
- case 0x65:
- d = ((guint) value) >> amount;
- break;
- default:
- g_assert_not_reached ();
- return JS_FALSE;
- }
-
- cx->fp->sp--;
- return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_to_integer (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d = swfdec_value_to_number (cx, cx->fp->sp[-1]);
-
- return JS_NewNumberValue (cx, (int) d, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_target_path (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecMovie *movie = swfdec_scriptable_from_jsval (cx, cx->fp->sp[-1], SWFDEC_TYPE_MOVIE);
-
- if (movie == NULL) {
- cx->fp->sp[-1] = JSVAL_VOID;
- } else {
- char *s = swfdec_movie_get_path (movie);
- JSString *string = JS_NewStringCopyZ (cx, s);
- g_free (s);
- if (string == NULL)
- return JS_FALSE;
- cx->fp->sp[-1] = STRING_TO_JSVAL (string);
- }
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_define_local (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *name;
-
- g_assert (cx->fp->scopeChain != NULL);
- name = swfdec_js_to_string (cx, cx->fp->sp[-2]);
- if (name == NULL)
- return JS_FALSE;
- if (!JS_SetProperty (cx, cx->fp->scopeChain, name, &cx->fp->sp[-1]))
- return JS_FALSE;
- cx->fp->sp -= 2;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_define_local2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *name;
- jsval val = JSVAL_VOID;
-
- g_assert (cx->fp->scopeChain != NULL);
- name = swfdec_js_to_string (cx, cx->fp->sp[-1]);
- if (name == NULL)
- return JS_FALSE;
- if (!JS_SetProperty (cx, cx->fp->scopeChain, name, &val))
- return JS_FALSE;
- cx->fp->sp--;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_return (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecScript *script = cx->fp->swf;
-
- cx->fp->rval = cx->fp->sp[-1];
- cx->fp->pc = script->buffer->data + script->buffer->length;
- cx->fp->sp--;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_delete (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *name;
-
- cx->fp->sp -= 2;
- name = swfdec_js_to_string (cx, cx->fp->sp[1]);
- if (name == NULL)
- return JS_FALSE;
- if (!JSVAL_IS_OBJECT (cx->fp->sp[0]))
- return JS_TRUE;
- return JS_DeleteProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[0]), name);
-}
-
-static JSBool
-swfdec_action_delete2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- const char *name;
- JSObject *obj, *pobj;
- JSProperty *prop;
- JSAtom *atom;
-
- cx->fp->sp -= 1;
- name = swfdec_js_to_string (cx, cx->fp->sp[1]);
- if (name == NULL)
- return JS_FALSE;
- if (!(atom = js_Atomize (cx, name, strlen (name), 0)) ||
- !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop))
- return JS_FALSE;
- if (!pobj)
- return JS_TRUE;
- return JS_DeleteProperty (cx, pobj, name);
-}
-
-static JSBool
-swfdec_action_store_register (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- if (len != 1) {
- SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len);
- return JS_FALSE;
- }
- if (!swfdec_action_has_register (cx, *data)) {
- SWFDEC_ERROR ("Cannot store into register %u, not enough registers", (guint) *data);
- return JS_FALSE;
- }
- cx->fp->vars[*data] = cx->fp->sp[-1];
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_modulo_5 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double x, y;
-
- x = swfdec_value_to_number (cx, cx->fp->sp[-1]);
- y = swfdec_value_to_number (cx, cx->fp->sp[-2]);
- cx->fp->sp--;
- errno = 0;
- x = fmod (x, y);
- if (errno != 0) {
- cx->fp->sp[-1] = DOUBLE_TO_JSVAL (cx->runtime->jsNaN);
- return JS_TRUE;
- } else {
- return JS_NewNumberValue (cx, x, &cx->fp->sp[-1]);
- }
-}
-
-static JSBool
-swfdec_action_modulo_7 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double x, y;
-
- if (!swfdec_value_to_number_7 (cx, cx->fp->sp[-1], &x) ||
- !swfdec_value_to_number_7 (cx, cx->fp->sp[-2], &y))
- return JS_FALSE;
- cx->fp->sp--;
- errno = 0;
- x = fmod (x, y);
- if (errno != 0) {
- cx->fp->sp[-1] = DOUBLE_TO_JSVAL (cx->runtime->jsNaN);
- return JS_TRUE;
- } else {
- return JS_NewNumberValue (cx, x, &cx->fp->sp[-1]);
- }
-}
-
-static JSBool
-swfdec_action_swap (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval tmp = cx->fp->sp[-2];
- cx->fp->sp[-2] = cx->fp->sp[-1];
- cx->fp->sp[-1] = tmp;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_to_number (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- double d;
- if (!JS_ValueToNumber (cx, cx->fp->sp[-1], &d))
- return JS_FALSE;
- return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]);
-}
-
-static JSBool
-swfdec_action_to_string (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSString *s;
- s = JS_ValueToString(cx, cx->fp->sp[-1]);
- if (!s)
- return JS_FALSE;
- cx->fp->sp[-1] = STRING_TO_JSVAL (s);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_type_of (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval val;
- const char *type;
- JSString *string;
-
- val = cx->fp->sp[-1];
- if (JSVAL_IS_NUMBER (val)) {
- type = "number";
- } else if (JSVAL_IS_BOOLEAN (val)) {
- type = "boolean";
- } else if (JSVAL_IS_STRING (val)) {
- type = "string";
- } else if (JSVAL_IS_VOID (val)) {
- type = "undefined";
- } else if (JSVAL_IS_NULL (val)) {
- type = "null";
- } else if (JSVAL_IS_OBJECT (val)) {
- JSObject *obj = JSVAL_TO_OBJECT (val);
- if (swfdec_js_is_movieclip (cx, obj)) {
- type = "movieclip";
- } else if (JS_ObjectIsFunction (cx, obj)) {
- type = "function";
- } else {
- type = "object";
- }
- } else {
- g_assert_not_reached ();
- return JS_FALSE;
- }
- /* can't use InternString here because of case sensitivity issues */
- string = JS_NewStringCopyZ (cx, type);
- if (string == NULL)
- return JS_FALSE;
- cx->fp->sp[-1] = STRING_TO_JSVAL (string);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_get_time (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- SwfdecPlayer *player = JS_GetContextPrivate (cx);
-
- *cx->fp->sp++ = INT_TO_JSVAL ((int) SWFDEC_TICKS_TO_MSECS (player->time));
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_extends (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- jsval superclass, subclass, proto;
- JSObject *prototype;
-
- superclass = cx->fp->sp[-1];
- subclass = cx->fp->sp[-2];
- cx->fp->sp -= 2;
- if (!JSVAL_IS_OBJECT (superclass) || superclass == JSVAL_NULL ||
- !JSVAL_IS_OBJECT (subclass) || subclass == JSVAL_NULL) {
- SWFDEC_ERROR ("superclass or subclass aren't objects");
- return JS_TRUE;
- }
- if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (superclass), "prototype", &proto) ||
- !JSVAL_IS_OBJECT (proto))
- return JS_FALSE;
- prototype = JS_NewObject (cx, NULL, JSVAL_TO_OBJECT (proto), NULL);
- if (prototype == NULL)
- return JS_FALSE;
- proto = OBJECT_TO_JSVAL (prototype);
- if (!JS_SetProperty (cx, prototype, "__constructor__", &superclass) ||
- !JS_SetProperty (cx, JSVAL_TO_OBJECT (subclass), "prototype", &proto))
- return JS_FALSE;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_enumerate2 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSObject *obj;
- JSIdArray *array;
- guint i;
-
- if (!JSVAL_IS_OBJECT (cx->fp->sp[-1]) || cx->fp->sp[-1] == JSVAL_NULL) {
- SWFDEC_ERROR ("Enumerate2 called without an object");
- cx->fp->sp[-1] = JSVAL_NULL;
- return JS_TRUE;
- }
- obj = JSVAL_TO_OBJECT (cx->fp->sp[-1]);
- cx->fp->sp[-1] = JSVAL_NULL;
- array = JS_Enumerate (cx, obj);
- if (!array)
- return JS_FALSE;
- if ((guint) (cx->fp->spend - cx->fp->sp) < array->length) {
- SWFDEC_ERROR ("FIXME: not enough stack space, need %u, got %td",
- array->length, cx->fp->spend - cx->fp->sp);
- JS_DestroyIdArray (cx, array);
- return JS_FALSE;
- }
- for (i = 0; i < array->length; i++) {
- if (!JS_IdToValue (cx, array->vector[i], cx->fp->sp++)) {
- JS_DestroyIdArray (cx, array);
- return JS_FALSE;
- }
- }
- JS_DestroyIdArray (cx, array);
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_logical_5 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSBool l, r;
-
- l = swfdec_value_to_boolean_5 (cx, cx->fp->sp[-1]);
- r = swfdec_value_to_boolean_5 (cx, cx->fp->sp[-2]);
-
- cx->fp->sp--;
- if (action == 0x10)
- cx->fp->sp[-1] = l && r ? JSVAL_TRUE : JSVAL_FALSE;
- else
- cx->fp->sp[-1] = l || r ? JSVAL_TRUE : JSVAL_FALSE;
- return JS_TRUE;
-}
-
-static JSBool
-swfdec_action_logical_7 (JSContext *cx, guint action, const guint8 *data, guint len)
-{
- JSBool l, r;
-
- l = swfdec_value_to_boolean_7 (cx, cx->fp->sp[-1]);
- r = swfdec_value_to_boolean_7 (cx, cx->fp->sp[-2]);
-
- cx->fp->sp--;
- if (action == 0x10)
- cx->fp->sp[-1] = l && r ? JSVAL_TRUE : JSVAL_FALSE;
- else
- cx->fp->sp[-1] = l || r ? JSVAL_TRUE : JSVAL_FALSE;
- return JS_TRUE;
-}
-
-/*** PRINT FUNCTIONS ***/
-
-static char *
-swfdec_action_print_store_register (guint action, const guint8 *data, guint len)
-{
- if (len != 1) {
- SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len);
- return NULL;
- }
- return g_strdup_printf ("StoreRegister %u", (guint) *data);
-}
-
-static char *
-swfdec_action_print_set_target (guint action, const guint8 *data, guint len)
-{
- if (!memchr (data, 0, len)) {
- SWFDEC_ERROR ("SetTarget action does not specify a string");
- return JS_FALSE;
- }
- return g_strconcat ("SetTarget ", data, NULL);
-}
-
-static char *
-swfdec_action_print_define_function (guint action, const guint8 *data, guint len)
-{
- SwfdecBits bits;
- GString *string;
- const char *function_name;
- guint i, n_args, size;
- gboolean v2 = (action == 0x8e);
-
- string = g_string_new (v2 ? "DefineFunction2 " : "DefineFunction ");
- swfdec_bits_init_data (&bits, data, len);
- function_name = swfdec_bits_get_string (&bits);
- if (function_name == NULL) {
- SWFDEC_ERROR ("could not parse function name");
- g_string_free (string, TRUE);
- return NULL;
- }
- if (*function_name) {
- g_string_append (string, function_name);
- g_string_append_c (string, ' ');
- }
- n_args = swfdec_bits_get_u16 (&bits);
- g_string_append_c (string, '(');
- if (v2) {
- /* n_regs = */ swfdec_bits_get_u8 (&bits);
- /* flags = */ swfdec_bits_get_u16 (&bits);
- }
-
- for (i = 0; i < n_args; i++) {
- guint preload;
- const char *arg_name;
- if (v2)
- preload = swfdec_bits_get_u8 (&bits);
- else
- preload = 0;
- arg_name = swfdec_bits_get_string (&bits);
- if (preload == 0 && (arg_name == NULL || *arg_name == '\0')) {
- SWFDEC_ERROR ("empty argument name not allowed");
- g_string_free (string, TRUE);
- return NULL;
- }
- if (i)
- g_string_append (string, ", ");
- if (preload)
- g_string_append_printf (string, "PRELOAD %u", preload);
- else
- g_string_append (string, arg_name);
- }
- g_string_append_c (string, ')');
- size = swfdec_bits_get_u16 (&bits);
- g_string_append_printf (string, " %u", size);
- return g_string_free (string, FALSE);
-}
-
-static char *
-swfdec_action_print_get_url2 (guint action, const guint8 *data, guint len)
-{
- guint method;
-
- if (len != 1) {
- SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len);
- return NULL;
- }
- method = data[0] >> 6;
- if (method == 3) {
- SWFDEC_ERROR ("GetURL method 3 invalid");
- method = 0;
- }
- if (method) {
- SWFDEC_ERROR ("FIXME: implement encoding variables using %s", method == 1 ? "GET" : "POST");
- }
- return g_strdup_printf ("GetURL2%s%s%s", method == 0 ? "" : (method == 1 ? " GET" : " POST"),
- data[0] & 2 ? " LoadTarget" : "", data[0] & 1 ? " LoadVariables" : "");
-}
-
-static char *
-swfdec_action_print_get_url (guint action, const guint8 *data, guint len)
-{
- SwfdecBits bits;
- const char *url, *target;
-
- swfdec_bits_init_data (&bits, data, len);
- url = swfdec_bits_skip_string (&bits);
- target = swfdec_bits_skip_string (&bits);
- if (swfdec_bits_left (&bits)) {
- SWFDEC_WARNING ("leftover bytes in GetURL action");
- }
- return g_strdup_printf ("GetURL %s %s", url, target);
-}
-
-static char *
-swfdec_action_print_if (guint action, const guint8 *data, guint len)
-{
- if (len != 2) {
- SWFDEC_ERROR ("If action length invalid (is %u, should be 2", len);
- return NULL;
- }
- return g_strdup_printf ("If %d", GINT16_FROM_LE (*((gint16*) data)));
-}
-
-static char *
-swfdec_action_print_jump (guint action, const guint8 *data, guint len)
-{
- if (len != 2) {
- SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len);
- return NULL;
- }
- return g_strdup_printf ("Jump %d", GINT16_FROM_LE (*((gint16*) data)));
-}
-
-static char *
-swfdec_action_print_push (guint action, const guint8 *data, guint len)
-{
- gboolean first = TRUE;
- SwfdecBits bits;
- GString *string = g_string_new ("Push");
-
- swfdec_bits_init_data (&bits, data, len);
- while (swfdec_bits_left (&bits)) {
- guint type = swfdec_bits_get_u8 (&bits);
- if (first)
- g_string_append (string, " ");
- else
- g_string_append (string, ", ");
- first = FALSE;
- switch (type) {
- case 0: /* string */
- {
- const char *s = swfdec_bits_skip_string (&bits);
- if (!s) {
- g_string_free (string, TRUE);
- return NULL;
- }
- g_string_append_c (string, '"');
- g_string_append (string, s);
- g_string_append_c (string, '"');
- break;
- }
- case 1: /* float */
- g_string_append_printf (string, "%g", swfdec_bits_get_float (&bits));
- break;
- case 2: /* null */
- g_string_append (string, "null");
- break;
- case 3: /* undefined */
- g_string_append (string, "void");
- break;
- case 4: /* register */
- g_string_append_printf (string, "Register %u", swfdec_bits_get_u8 (&bits));
- break;
- case 5: /* boolean */
- g_string_append (string, swfdec_bits_get_u8 (&bits) ? "True" : "False");
- break;
- case 6: /* double */
- g_string_append_printf (string, "%g", swfdec_bits_get_double (&bits));
- break;
- case 7: /* 32bit int */
- g_string_append_printf (string, "%d", swfdec_bits_get_u32 (&bits));
- break;
- case 8: /* 8bit ConstantPool address */
- g_string_append_printf (string, "Pool %u", swfdec_bits_get_u8 (&bits));
- break;
- case 9: /* 16bit ConstantPool address */
- g_string_append_printf (string, "Pool %u", swfdec_bits_get_u16 (&bits));
- break;
- default:
- SWFDEC_ERROR ("Push: type %u not implemented", type);
- return JS_FALSE;
- }
- }
- return g_string_free (string, FALSE);
-}
-
-/* NB: constant pool actions are special in that they are called at init time */
-static char *
-swfdec_action_print_constant_pool (guint action, const guint8 *data, guint len)
-{
- guint i;
- GString *string;
- SwfdecConstantPool *pool;
-
- pool = swfdec_constant_pool_new_from_action (data, len);
- if (pool == NULL)
- return JS_FALSE;
- string = g_string_new ("ConstantPool");
- for (i = 0; i < swfdec_constant_pool_size (pool); i++) {
- g_string_append (string, i ? ", " : " ");
- g_string_append (string, swfdec_constant_pool_get (pool, i));
- g_string_append_printf (string, " (%u)", i);
- }
- return g_string_free (string, FALSE);
-}
-
-static char *
-swfdec_action_print_wait_for_frame2 (guint action, const guint8 *data, guint len)
-{
- if (len != 1) {
- SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
- return NULL;
- }
- return g_strdup_printf ("WaitForFrame2 %u", (guint) *data);
-}
-
-static char *
-swfdec_action_print_goto_frame2 (guint action, const guint8 *data, guint len)
-{
- gboolean play, bias;
- SwfdecBits bits;
-
- swfdec_bits_init_data (&bits, data, len);
- if (swfdec_bits_getbits (&bits, 6)) {
- SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
- }
- bias = swfdec_bits_getbit (&bits);
- play = swfdec_bits_getbit (&bits);
- if (bias) {
- return g_strdup_printf ("GotoFrame2 %s +%u", play ? "play" : "stop",
- swfdec_bits_get_u16 (&bits));
- } else {
- return g_strdup_printf ("GotoFrame2 %s", play ? "play" : "stop");
- }
-}
-
-static char *
-swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len)
-{
- guint frame;
-
- if (len != 2)
- return NULL;
-
- frame = GUINT16_FROM_LE (*((guint16 *) data));
- return g_strdup_printf ("GotoFrame %u", frame);
-}
-
-static char *
-swfdec_action_print_goto_label (guint action, const guint8 *data, guint len)
-{
- if (!memchr (data, 0, len)) {
- SWFDEC_ERROR ("GotoLabel action does not specify a string");
- return NULL;
- }
-
- return g_strdup_printf ("GotoLabel %s", data);
-}
-
-static char *
-swfdec_action_print_wait_for_frame (guint action, const guint8 *data, guint len)
-{
- guint frame, jump;
-
- if (len != 3)
- return NULL;
-
- frame = GUINT16_FROM_LE (*((guint16 *) data));
- jump = data[2];
- return g_strdup_printf ("WaitForFrame %u %u", frame, jump);
-}
-#endif
-
-/*** BIG FUNCTION TABLE ***/
-
-/* defines minimum and maximum versions for which we have seperate scripts */
-#define MINSCRIPTVERSION 3
-#define MAXSCRIPTVERSION 7
-#define EXTRACT_VERSION(v) MIN ((v) - MINSCRIPTVERSION, MAXSCRIPTVERSION - MINSCRIPTVERSION)
-
-typedef void (* SwfdecActionExec) (SwfdecAsContext *cx, guint action, const guint8 *data, guint len);
-typedef struct {
- const char * name; /* name identifying the action */
- char * (* print) (guint action, const guint8 *data, guint len);
- int remove; /* values removed from stack or -1 for dynamic */
- int add; /* values added to the stack or -1 for dynamic */
- SwfdecActionExec exec[MAXSCRIPTVERSION - MINSCRIPTVERSION + 1];
- /* array is for version 3, 4, 5, 6, 7+ */
-} SwfdecActionSpec;
-
-const SwfdecActionSpec actions[256] = {
-#if 0
- /* version 3 */
- [0x04] = { "NextFrame", NULL, 0, 0, { swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame } },
- [0x05] = { "PreviousFrame", NULL, 0, 0, { swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame } },
- [0x06] = { "Play", NULL, 0, 0, { swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play } },
- [0x07] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } },
- [0x08] = { "ToggleQuality", NULL },
- [0x09] = { "StopSounds", NULL, 0, 0, { swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds, swfdec_action_stop_sounds } },
- /* version 4 */
- [0x0a] = { "Add", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
- [0x0b] = { "Subtract", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
- [0x0c] = { "Multiply", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
- [0x0d] = { "Divide", NULL, 2, 1, { NULL, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary, swfdec_action_binary } },
- [0x0e] = { "Equals", NULL, 2, 1, { NULL, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare } },
- [0x0f] = { "Less", NULL, 2, 1, { NULL, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare, swfdec_action_old_compare } },
- [0x10] = { "And", NULL, 2, 1, { NULL, /* FIXME */NULL, swfdec_action_logical_5, swfdec_action_logical_5, swfdec_action_logical_7 } },
- [0x11] = { "Or", NULL, 2, 1, { NULL, /* FIXME */NULL, swfdec_action_logical_5, swfdec_action_logical_5, swfdec_action_logical_7 } },
- [0x12] = { "Not", NULL, 1, 1, { NULL, swfdec_action_not_4, swfdec_action_not_5, swfdec_action_not_5, swfdec_action_not_5 } },
- [0x13] = { "StringEquals", NULL },
- [0x14] = { "StringLength", NULL },
- [0x15] = { "StringExtract", NULL },
- [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } },
- [0x18] = { "ToInteger", NULL, 1, 1, { NULL, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer } },
- [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } },
- [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } },
- [0x20] = { "SetTarget2", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } },
- [0x21] = { "StringAdd", NULL, 2, 1, { NULL, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add } },
- [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } },
- [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } },
- [0x24] = { "CloneSprite", NULL },
- [0x25] = { "RemoveSprite", NULL },
- [0x26] = { "Trace", NULL, 1, 0, { NULL, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace, swfdec_action_trace } },
- [0x27] = { "StartDrag", NULL, -1, 0, { NULL, swfdec_action_start_drag, swfdec_action_start_drag, swfdec_action_start_drag, swfdec_action_start_drag } },
- [0x28] = { "EndDrag", NULL, 0, 0, { NULL, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag, swfdec_action_end_drag } },
- [0x29] = { "StringLess", NULL },
- /* version 7 */
- [0x2a] = { "Throw", NULL },
- [0x2b] = { "Cast", NULL },
- [0x2c] = { "Implements", NULL },
- /* version 4 */
- [0x30] = { "RandomNumber", NULL, 1, 1, { NULL, swfdec_action_random_number, swfdec_action_random_number, swfdec_action_random_number, swfdec_action_random_number } },
- [0x31] = { "MBStringLength", NULL },
- [0x32] = { "CharToAscii", NULL },
- [0x33] = { "AsciiToChar", NULL },
- [0x34] = { "GetTime", NULL, 0, 1, { NULL, swfdec_action_get_time, swfdec_action_get_time, swfdec_action_get_time, swfdec_action_get_time } },
- [0x35] = { "MBStringExtract", NULL },
- [0x36] = { "MBCharToAscii", NULL },
- [0x37] = { "MVAsciiToChar", NULL },
- /* version 5 */
- [0x3a] = { "Delete", NULL, 2, 0, { NULL, NULL, swfdec_action_delete, swfdec_action_delete, swfdec_action_delete } },
- [0x3b] = { "Delete2", NULL, 1, 0, { NULL, NULL, swfdec_action_delete2, swfdec_action_delete2, swfdec_action_delete2 } },
- [0x3c] = { "DefineLocal", NULL, 2, 0, { NULL, NULL, swfdec_action_define_local, swfdec_action_define_local, swfdec_action_define_local } },
- [0x3d] = { "CallFunction", NULL, -1, 1, { NULL, NULL, swfdec_action_call_function, swfdec_action_call_function, swfdec_action_call_function } },
- [0x3e] = { "Return", NULL, 1, 0, { NULL, NULL, swfdec_action_return, swfdec_action_return, swfdec_action_return } },
- [0x3f] = { "Modulo", NULL, 2, 1, { NULL, NULL, swfdec_action_modulo_5, swfdec_action_modulo_5, swfdec_action_modulo_7 } },
- [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } },
- [0x41] = { "DefineLocal2", NULL, 1, 0, { NULL, NULL, swfdec_action_define_local2, swfdec_action_define_local2, swfdec_action_define_local2 } },
- [0x42] = { "InitArray", NULL, -1, 1, { NULL, NULL, swfdec_action_init_array, swfdec_action_init_array, swfdec_action_init_array } },
- [0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } },
- [0x44] = { "TypeOf", NULL, 1, 1, { NULL, NULL, swfdec_action_type_of, swfdec_action_type_of, swfdec_action_type_of } },
- [0x45] = { "TargetPath", NULL, 1, 1, { NULL, NULL, swfdec_action_target_path, swfdec_action_target_path, swfdec_action_target_path } },
- [0x46] = { "Enumerate", NULL },
- [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } },
- [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } },
- [0x49] = { "Equals2", NULL, 2, 1, { NULL, NULL, swfdec_action_equals2, swfdec_action_equals2, swfdec_action_equals2 } },
- [0x4a] = { "ToNumber", NULL, 1, 1, { NULL, NULL, swfdec_action_to_number, swfdec_action_to_number, swfdec_action_to_number } },
- [0x4b] = { "ToString", NULL, 1, 1, { NULL, NULL, swfdec_action_to_string, swfdec_action_to_string, swfdec_action_to_string } },
- [0x4c] = { "PushDuplicate", NULL, 1, 2, { NULL, NULL, swfdec_action_push_duplicate, swfdec_action_push_duplicate, swfdec_action_push_duplicate } },
- [0x4d] = { "Swap", NULL, 2, 2, { NULL, NULL, swfdec_action_swap, swfdec_action_swap, swfdec_action_swap } },
- [0x4e] = { "GetMember", NULL, 2, 1, { NULL, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member, swfdec_action_get_member } },
- [0x4f] = { "SetMember", NULL, 3, 0, { NULL, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member, swfdec_action_set_member } },
- [0x50] = { "Increment", NULL, 1, 1, { NULL, NULL, swfdec_action_increment, swfdec_action_increment, swfdec_action_increment } },
- [0x51] = { "Decrement", NULL, 1, 1, { NULL, NULL, swfdec_action_decrement, swfdec_action_decrement, swfdec_action_decrement } },
- [0x52] = { "CallMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_call_method, swfdec_action_call_method, swfdec_action_call_method } },
- [0x53] = { "NewMethod", NULL, -1, 1, { NULL, NULL, swfdec_action_new_method, swfdec_action_new_method, swfdec_action_new_method } },
- /* version 6 */
- [0x54] = { "InstanceOf", NULL },
- [0x55] = { "Enumerate2", NULL, 1, -1, { NULL, NULL, NULL, swfdec_action_enumerate2, swfdec_action_enumerate2 } },
- /* version 5 */
- [0x60] = { "BitAnd", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } },
- [0x61] = { "BitOr", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } },
- [0x62] = { "BitXor", NULL, 2, 1, { NULL, NULL, swfdec_action_bitwise, swfdec_action_bitwise, swfdec_action_bitwise } },
- [0x63] = { "BitLShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } },
- [0x64] = { "BitRShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } },
- [0x65] = { "BitURShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } },
- /* version 6 */
- [0x66] = { "StrictEquals", NULL },
- [0x67] = { "Greater", NULL, 2, 1, { NULL, NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } },
- [0x68] = { "StringGreater", NULL },
- /* version 7 */
- [0x69] = { "Extends", NULL, 2, 0, { NULL, NULL, NULL, NULL, swfdec_action_extends } },
-
- /* version 3 */
- [0x81] = { "GotoFrame", swfdec_action_print_goto_frame, 0, 0, { swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame, swfdec_action_goto_frame } },
- [0x83] = { "GetURL", swfdec_action_print_get_url, 0, 0, { swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url, swfdec_action_get_url } },
- /* version 5 */
- [0x87] = { "StoreRegister", swfdec_action_print_store_register, 1, 1, { NULL, NULL, swfdec_action_store_register, swfdec_action_store_register, swfdec_action_store_register } },
- [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } },
- /* version 3 */
- [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } },
- [0x8b] = { "SetTarget", swfdec_action_print_set_target, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } },
- [0x8c] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } },
- /* version 4 */
- [0x8d] = { "WaitForFrame2", swfdec_action_print_wait_for_frame2, 1, 0, { NULL, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2, swfdec_action_wait_for_frame2 } },
- /* version 7 */
- [0x8e] = { "DefineFunction2", swfdec_action_print_define_function, 0, -1, { NULL, NULL, NULL, swfdec_action_define_function, swfdec_action_define_function } },
- [0x8f] = { "Try", NULL },
- /* version 5 */
- [0x94] = { "With", NULL },
- /* version 4 */
- [0x96] = { "Push", swfdec_action_print_push, 0, -1, { NULL, swfdec_action_push, swfdec_action_push, swfdec_action_push, swfdec_action_push } },
- [0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } },
- [0x9a] = { "GetURL2", swfdec_action_print_get_url2, 2, 0, { NULL, swfdec_action_get_url2, swfdec_action_get_url2, swfdec_action_get_url2, swfdec_action_get_url2 } },
- /* version 5 */
- [0x9b] = { "DefineFunction", swfdec_action_print_define_function, 0, -1, { NULL, NULL, swfdec_action_define_function, swfdec_action_define_function, swfdec_action_define_function } },
- /* version 4 */
- [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } },
- [0x9e] = { "Call", NULL },
- [0x9f] = { "GotoFrame2", swfdec_action_print_goto_frame2, 1, 0, { NULL, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2 } }
-#endif
-};
-
char *
swfdec_script_print_action (guint action, const guint8 *data, guint len)
{
- const SwfdecActionSpec *spec = actions + action;
+ const SwfdecActionSpec *spec = swfdec_as_actions + action;
if (action & 0x80) {
if (spec->print == NULL) {
@@ -2649,14 +215,13 @@ static gboolean
validate_action (gconstpointer bytecode, guint action, const guint8 *data, guint len, gpointer scriptp)
{
SwfdecScript *script = scriptp;
- int version = EXTRACT_VERSION (script->version);
+ int version = SWFDEC_AS_EXTRACT_SCRIPT_VERSION (script->version);
- /* ensure there's a function to execute this opcode, otherwise fail */
- if (actions[action].exec[version] == NULL) {
- SWFDEC_ERROR ("no function for %u %s in v%u", action,
- actions[action].name ? actions[action].name : "Unknown",
+ /* warn if there's no function to execute this opcode */
+ if (swfdec_as_actions[action].exec[version] == NULL) {
+ SWFDEC_ERROR ("no function for %3u 0x%02X %s in v%u", action, action,
+ swfdec_as_actions[action].name ? swfdec_as_actions[action].name : "Unknown",
script->version);
- return FALSE;
}
/* we might want to do stuff here for certain actions */
#if 0
@@ -2693,7 +258,7 @@ swfdec_script_new (SwfdecBits *bits, con
g_return_val_if_fail (bits != NULL, NULL);
- if (version < MINSCRIPTVERSION) {
+ if (version < SWFDEC_AS_MIN_SCRIPT_VERSION) {
SWFDEC_ERROR ("swfdec version %u doesn't support scripts", version);
return NULL;
}
@@ -2754,340 +319,6 @@ swfdec_script_unref (SwfdecScript *scrip
g_free (script);
}
-#if 0
-JSBool
-swfdec_script_interpret (SwfdecScript *script, JSContext *cx, jsval *rval)
-{
- JSStackFrame *fp;
- guint8 *startpc, *pc, *endpc, *nextpc;
- JSBool ok = JS_TRUE;
- void *mark;
- jsval *startsp;
-#ifndef G_DISABLE_ASSERT
- jsval *checksp;
-#endif
- int stack_check;
- guint action, len;
- guint8 *data;
- guint version;
- const SwfdecActionSpec *spec;
-
- /* set up general stuff */
- swfdec_script_ref (script);
- version = EXTRACT_VERSION (script->version);
- *rval = JSVAL_VOID;
- fp = cx->fp;
- /* do the preloading */
- if (script->preloads) {
- guint i;
- for (i = 0; i < fp->fun->nargs; i++) {
- if (script->preloads[i])
- fp->vars[script->preloads[i]] = fp->argv[i];
- }
- }
- if (script->flags) {
- guint preload_reg = 1;
- SwfdecPlayer *player = JS_GetContextPrivate (cx);
- if (script->flags & SWFDEC_SCRIPT_PRELOAD_THIS)
- fp->vars[preload_reg++] = OBJECT_TO_JSVAL (fp->thisp);
- if (script->flags & SWFDEC_SCRIPT_PRELOAD_ARGS) {
- if (!JS_GetProperty (cx, fp->scopeChain, "arguments", &fp->vars[preload_reg++])) {
- ok = JS_FALSE;
- goto out;
- }
- }
- if (script->flags & SWFDEC_SCRIPT_SUPPRESS_ARGS) {
- /* FIXME: keep in sync with jsfun.c */
- fp->flags |= JS_BIT (JSFRAME_OVERRIDE_SHIFT);
- }
- if (script->flags & SWFDEC_SCRIPT_PRELOAD_SUPER) {
- if (!JS_GetProperty (cx, JS_GetPrototype (cx, fp->thisp),
- fp->flags & JSINVOKE_CONSTRUCT ? "__constructor__" : "__proto__",
- &fp->vars[preload_reg++])) {
- ok = JS_FALSE;
- goto out;
- }
- }
- if (script->flags & SWFDEC_SCRIPT_PRELOAD_ROOT) {
- JSAtom *atom;
- JSObject *obj, *pobj;
- JSProperty *prop;
- SWFDEC_LOG ("preloading root into register %u", preload_reg);
- if (!(atom = js_Atomize (cx, "_root", 5, 0)) ||
- !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop) ||
- !js_GetProperty (cx, obj, (jsid) atom, &fp->vars[preload_reg++])) {
- ok = JS_FALSE;
- goto out;
- }
- }
- if (script->flags & SWFDEC_SCRIPT_PRELOAD_PARENT) {
- JSAtom *atom;
- JSObject *obj, *pobj;
- JSProperty *prop;
- SWFDEC_LOG ("preloading parent into register %u", preload_reg);
- if (!(atom = js_Atomize (cx, "_parent", 7, 0)) ||
- !js_FindProperty (cx, (jsid) atom, &obj, &pobj, &prop) ||
- !js_GetProperty (cx, obj, (jsid) atom, &fp->vars[preload_reg++])) {
- ok = JS_FALSE;
- goto out;
- }
- }
- if (script->flags & SWFDEC_SCRIPT_PRELOAD_GLOBAL)
- fp->vars[preload_reg++] = OBJECT_TO_JSVAL (player->jsobj);
- }
- /* set up the script */
- startpc = pc = script->buffer->data;
- endpc = startpc + script->buffer->length;
- fp->pc = pc;
- /* set up stack */
- startsp = js_AllocRawStack (cx, STACKSIZE, &mark);
- if (!startsp) {
- ok = JS_FALSE;
- goto out;
- }
- fp->spbase = startsp;
- fp->spend = startsp + STACKSIZE;
- fp->sp = startsp;
- /* Check for too much nesting, or too deep a C stack. */
- if (++cx->interpLevel == MAX_INTERP_LEVEL ||
- !JS_CHECK_STACK_SIZE(cx, stack_check)) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
- ok = JS_FALSE;
- goto out;
- }
- /* initialize the constant pool */
- if (script->constant_pool) {
- spec = actions + 0x88;
- ok = spec->exec[version] (cx, 0x88, script->constant_pool->data + 3,
- script->constant_pool->length - 3);
- if (!ok) {
- SWFDEC_WARNING ("Constant pool initialization failed");
- goto out;
- }
- }
-
- while (TRUE) {
- /* check pc */
- if (pc == endpc) {
- /* scripts created via DefineFunction or the Return action use this way out */
- *rval = fp->rval;
- break;
- }
- if (pc < startpc || pc >= endpc) {
- SWFDEC_ERROR ("pc %p not in valid range [%p, %p) anymore", pc, startpc, endpc);
- goto internal_error;
- }
-
- /* run interrupt handler */
- if (cx->runtime->interruptHandler) {
- jsval tmp;
- switch (cx->runtime->interruptHandler (cx, NULL, pc, &tmp,
- cx->runtime->interruptHandlerData)) {
- case JSTRAP_ERROR:
- ok = JS_FALSE;
- goto out;
- case JSTRAP_CONTINUE:
- break;
- case JSTRAP_RETURN:
- fp->rval = tmp;
- goto out;
- case JSTRAP_THROW:
- cx->throwing = JS_TRUE;
- cx->exception = tmp;
- ok = JS_FALSE;
- goto out;
- default:
- g_assert_not_reached ();
- break;
- }
- }
-
- /* decode next action */
- action = *pc;
- spec = actions + action;
- if (action == 0)
- break;
- if (action & 0x80) {
- if (pc + 2 >= endpc) {
- SWFDEC_ERROR ("action %u length value out of range", action);
- goto internal_error;
- }
- data = pc + 3;
- len = pc[1] | pc[2] << 8;
- if (data + len > endpc) {
- SWFDEC_ERROR ("action %u length %u out of range", action, len);
- goto internal_error;
- }
- nextpc = pc + 3 + len;
- } else {
- data = NULL;
- len = 0;
- nextpc = pc + 1;
- }
- /* check action is valid */
- if (spec->exec[version] == NULL) {
- SWFDEC_ERROR ("cannot interpret action %u %s for version %u", action,
- spec->name ? spec->name : "Unknown", script->version);
- goto internal_error;
- }
- if (spec->remove > 0 &&
- !swfdec_script_ensure_stack (cx, spec->remove)) {
- ok = JS_FALSE;
- goto out;
- }
- if (spec->add > 0 &&
- fp->sp + spec->add - MAX (spec->remove, 0) > fp->spend) {
- SWFDEC_ERROR ("FIXME: implement stack expansion, we got an overflow");
- goto internal_error;
- }
-#ifndef G_DISABLE_ASSERT
- checksp = (spec->add >= 0 && spec->remove >= 0) ? fp->sp + spec->add - spec->remove : NULL;
-#endif
- ok = spec->exec[version] (cx, action, data, len);
- if (!ok) {
- SWFDEC_WARNING ("action %s failed", spec->name);
- goto out;
- }
-#ifndef G_DISABLE_ASSERT
- if (checksp != NULL && checksp != fp->sp) {
- /* check stack was handled like expected */
- g_error ("action %s was supposed to change the stack by %d (+%d -%d), but it changed by %td",
- spec->name, spec->add - spec->remove, spec->add, spec->remove,
- fp->sp - checksp + spec->add - spec->remove);
- }
-#endif
- if (fp->pc == pc) {
- fp->pc = pc = nextpc;
- } else {
- pc = fp->pc;
- }
- }
-
-out:
-#if 0
- /* FIXME: exception handling */
- if (!ok && cx->throwing) {
- /*
- * Look for a try block within this frame that can catch the exception.
- */
- SCRIPT_FIND_CATCH_START(script, pc, pc);
- if (pc) {
- len = 0;
- cx->throwing = JS_FALSE; /* caught */
- ok = JS_TRUE;
- goto advance_pc;
- }
- }
-#endif
-no_catch:
-
- /* Reset sp before freeing stack slots, because our caller may GC soon. */
- fp->sp = fp->spbase;
- fp->spbase = NULL;
- if (fp->constant_pool) {
- swfdec_constant_pool_free (fp->constant_pool);
- fp->constant_pool = NULL;
- }
- js_FreeRawStack(cx, mark);
- cx->interpLevel--;
- swfdec_script_unref (script);
- return ok;
-
-internal_error:
- *rval = JSVAL_VOID;
- ok = JS_TRUE;
- goto no_catch;
-}
-
-/**
- * swfdec_script_execute:
- * @script: a #SwfdecScript to execute
- * @scriptable: #SwfdecScriptable to use as this in script scope
- *
- * Executes @script in the context of @scriptable. No local scope will be
- * added, so no local variables can exist. As per Actionscript, 4 registers
- * will be created.
- *
- * Returns: the return value of @script
- **/
-#endif
-void
-swfdec_script_execute (SwfdecScript *script, SwfdecScriptable *scriptable)
-{
-}
-#if 0
- JSContext *cx;
- JSStackFrame *oldfp, frame;
- JSObject *obj;
- JSBool ok;
- void *mark;
-
- g_return_val_if_fail (script != NULL, JSVAL_VOID);
- g_return_val_if_fail (SWFDEC_IS_SCRIPTABLE (scriptable), JSVAL_VOID);
-
- cx = scriptable->jscx;
- obj = swfdec_scriptable_get_object (scriptable);
- if (obj == NULL)
- return JSVAL_VOID;
- oldfp = cx->fp;
-
- frame.callobj = NULL;
- frame.script = NULL;
- frame.argsobj = NULL;
- frame.fun = swfdec_script_ensure_function (script, scriptable);
- frame.swf = script;
- frame.constant_pool = NULL;
- frame.thisp = obj;
- frame.argc = 0;
- frame.argv = NULL;
- frame.annotation = NULL;
- frame.sharpArray = NULL;
- frame.rval = JSVAL_VOID;
- frame.down = NULL;
- frame.pc = NULL;
- frame.sp = oldfp ? oldfp->sp : NULL;
- frame.spbase = NULL;
- frame.sharpDepth = 0;
- frame.flags = 0;
- frame.dormantNext = NULL;
- frame.objAtomMap = NULL;
- /* no local scope here */
- frame.scopeChain = obj;
- frame.varobj = obj;
- /* allocate stack for variables */
- frame.nvars = script->n_registers;
- frame.vars = js_AllocRawStack (cx, frame.nvars, &mark);
- if (frame.vars == NULL) {
- return JS_FALSE;
- }
- frame.vars[0] = frame.vars[1] = frame.vars[2] = frame.vars[3] = JSVAL_VOID;
-
- if (oldfp) {
- g_assert (!oldfp->dormantNext);
- oldfp->dormantNext = cx->dormantFrameChain;
- cx->dormantFrameChain = oldfp;
- }
- cx->fp = &frame;
-
- /*
- * Use frame.rval, not result, so the last result stays rooted across any
- * GC activations nested within this js_Interpret.
- */
- ok = swfdec_script_interpret (script, cx, &frame.rval);
-
- js_FreeRawStack (cx, mark);
-
- cx->fp = oldfp;
- if (oldfp) {
- g_assert (cx->dormantFrameChain == oldfp);
- cx->dormantFrameChain = oldfp->dormantNext;
- oldfp->dormantNext = NULL;
- }
-
- return ok ? frame.rval : JSVAL_VOID;
-}
-#endif
-
/*** UTILITY FUNCTIONS ***/
const char *
@@ -3095,7 +326,7 @@ swfdec_action_get_name (guint action)
{
g_return_val_if_fail (action < 256, NULL);
- return actions[action].name;
+ return swfdec_as_actions[action].name;
}
guint
@@ -3106,7 +337,7 @@ swfdec_action_get_from_name (const char
g_return_val_if_fail (name != NULL, 0);
for (i = 0; i < 256; i++) {
- if (actions[i].name && g_str_equal (name, actions[i].name))
+ if (swfdec_as_actions[i].name && g_str_equal (name, swfdec_as_actions[i].name))
return i;
}
return 0;
diff --git a/libswfdec/swfdec_script.h b/libswfdec/swfdec_script.h
index 673332a..0a3d966 100644
--- a/libswfdec/swfdec_script.h
+++ b/libswfdec/swfdec_script.h
@@ -66,10 +66,12 @@ guint swfdec_action_get_from_name (cons
SwfdecConstantPool *
swfdec_constant_pool_new_from_action (const guint8 * data,
guint len);
+void swfdec_constant_pool_free (SwfdecConstantPool * pool);
guint swfdec_constant_pool_size (SwfdecConstantPool * pool);
const char * swfdec_constant_pool_get (SwfdecConstantPool * pool,
guint i);
-void swfdec_constant_pool_free (SwfdecConstantPool * pool);
+SwfdecBuffer * swfdec_constant_pool_get_area (SwfdecScript * script,
+ SwfdecConstantPool * pool);
SwfdecScript * swfdec_script_new (SwfdecBits * bits,
const char * name,
diff-tree ee1c84df7a50b023262001feb21c90380798161a (from d7ed0cb12ed1506e74bd766fd0e88c66910f0f7f)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Apr 4 14:47:36 2007 +0200
implement some more of swfdec_as_value_to_string
diff --git a/libswfdec/swfdec_as_types.c b/libswfdec/swfdec_as_types.c
index 12f0d44..14cb0e4 100644
--- a/libswfdec/swfdec_as_types.c
+++ b/libswfdec/swfdec_as_types.c
@@ -62,18 +62,55 @@ const char *swfdec_as_strings[] = {
SWFDEC_AS_CONSTANT_STRING ("NetStream.Play.Start"),
SWFDEC_AS_CONSTANT_STRING ("NetStream.Play.Stop"),
SWFDEC_AS_CONSTANT_STRING ("NetStream.Play.StreamNotFound"),
+ SWFDEC_AS_CONSTANT_STRING ("undefined"),
+ SWFDEC_AS_CONSTANT_STRING ("null"),
+ SWFDEC_AS_CONSTANT_STRING ("[object Object]"),
+ SWFDEC_AS_CONSTANT_STRING ("true"),
+ SWFDEC_AS_CONSTANT_STRING ("false"),
/* add more here */
NULL
};
+/**
+ * swfdec_as_value_to_string:
+ * @context: a #SwfdecAsContext
+ * @value: value to be expressed as string
+ *
+ * Converts @value to a string.
+ * <warning>This function may run the garbage collector.</warning>
+ *
+ * Returns: a garbage-collected string representing @value
+ **/
const char *
swfdec_as_value_to_string (SwfdecAsContext *context, const SwfdecAsValue *value)
{
g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), SWFDEC_AS_STR_EMPTY);
g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), SWFDEC_AS_STR_EMPTY);
- if (SWFDEC_AS_VALUE_IS_STRING (value)) {
- return SWFDEC_AS_VALUE_GET_STRING (value);
+ switch (value->type) {
+ case SWFDEC_TYPE_AS_STRING:
+ return SWFDEC_AS_VALUE_GET_STRING (value);
+ case SWFDEC_TYPE_AS_UNDEFINED:
+ if (context->version > 6)
+ return SWFDEC_AS_STR_UNDEFINED;
+ else
+ return SWFDEC_AS_STR_EMPTY;
+ case SWFDEC_TYPE_AS_BOOLEAN:
+ return SWFDEC_AS_VALUE_GET_BOOLEAN (value) ? SWFDEC_AS_STR_TRUE : SWFDEC_AS_STR_FALSE;
+ case SWFDEC_TYPE_AS_NULL:
+ return SWFDEC_AS_STR_NULL;
+ case SWFDEC_TYPE_AS_NUMBER:
+ {
+ char *s = g_strdup_printf ("%g", SWFDEC_AS_VALUE_GET_NUMBER (value));
+ const char *ret = swfdec_as_context_get_string (context, s);
+ g_free (s);
+ return ret;
+ }
+ case SWFDEC_TYPE_AS_ASOBJECT:
+ /* FIXME! */
+ return SWFDEC_AS_STR_OBJECT_OBJECT;
+ default:
+ g_assert_not_reached ();
+ return SWFDEC_AS_STR_EMPTY;
}
- g_assert_not_reached ();
}
diff --git a/libswfdec/swfdec_as_types.h b/libswfdec/swfdec_as_types.h
index 92a7355..533df03 100644
--- a/libswfdec/swfdec_as_types.h
+++ b/libswfdec/swfdec_as_types.h
@@ -125,6 +125,11 @@ extern const char *swfdec_as_strings[];
#define SWFDEC_AS_STR_NETSTREAM_PLAY_START (swfdec_as_strings[31] + 1)
#define SWFDEC_AS_STR_NETSTREAM_PLAY_STOP (swfdec_as_strings[32] + 1)
#define SWFDEC_AS_STR_NETSTREAM_PLAY_STREAMNOTFOUND (swfdec_as_strings[33] + 1)
+#define SWFDEC_AS_STR_UNDEFINED (swfdec_as_strings[34] + 1)
+#define SWFDEC_AS_STR_NULL (swfdec_as_strings[35] + 1)
+#define SWFDEC_AS_STR_OBJECT_OBJECT (swfdec_as_strings[36] + 1)
+#define SWFDEC_AS_STR_TRUE (swfdec_as_strings[37] + 1)
+#define SWFDEC_AS_STR_FALSE (swfdec_as_strings[38] + 1)
/* all existing actions */
typedef enum {
diff-tree d7ed0cb12ed1506e74bd766fd0e88c66910f0f7f (from 4acdbf33dfad211c233f81a51f70d25e42676fc0)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Apr 4 14:46:58 2007 +0200
implement swfdec_as_object_run
diff --git a/libswfdec/swfdec_as_object.c b/libswfdec/swfdec_as_object.c
index 6f5ac61..a8cb206 100644
--- a/libswfdec/swfdec_as_object.c
+++ b/libswfdec/swfdec_as_object.c
@@ -23,6 +23,7 @@
#include "swfdec_as_object.h"
#include "swfdec_as_context.h"
+#include "swfdec_as_frame.h"
#include "swfdec_as_function.h"
#include "swfdec_debug.h"
@@ -263,8 +264,8 @@ swfdec_as_object_run (SwfdecAsObject *ob
g_return_if_fail (SWFDEC_AS_OBJECT_HAS_CONTEXT (object));
g_return_if_fail (script != NULL);
- g_assert_not_reached ();
- swfdec_as_context_run (object->context);
+ if (swfdec_as_frame_new (object, script))
+ swfdec_as_context_run (object->context);
}
void
diff-tree 4acdbf33dfad211c233f81a51f70d25e42676fc0 (from df9459902a3d4cc821233ce7a973c1284cb4ffcf)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Apr 4 14:46:21 2007 +0200
remember the number of registers
diff --git a/libswfdec/swfdec_as_frame.c b/libswfdec/swfdec_as_frame.c
index 8abf677..ca2d201 100644
--- a/libswfdec/swfdec_as_frame.c
+++ b/libswfdec/swfdec_as_frame.c
@@ -93,6 +93,7 @@ swfdec_as_frame_new (SwfdecAsObject *thi
if (!swfdec_as_context_use_mem (context, size))
return NULL;
frame = g_object_new (SWFDEC_TYPE_AS_FRAME, NULL);
+ SWFDEC_DEBUG ("new frame");
swfdec_as_object_add (SWFDEC_AS_OBJECT (frame), context, size);
frame->next = context->frame;
context->frame = frame;
@@ -101,7 +102,8 @@ swfdec_as_frame_new (SwfdecAsObject *thi
frame->stack = stack;
frame->scope = thisp;
frame->var_object = thisp;
- frame->registers = g_slice_alloc0 (sizeof (SwfdecAsValue) * script->n_registers);
+ frame->n_registers = script->n_registers;
+ frame->registers = g_slice_alloc0 (sizeof (SwfdecAsValue) * frame->n_registers);
SWFDEC_AS_VALUE_SET_OBJECT (&val, thisp);
swfdec_as_object_set (SWFDEC_AS_OBJECT (frame), SWFDEC_AS_STR_THIS, &val);
return frame;
More information about the Swfdec
mailing list