[Swfdec] Branch 'interpreter' - 20 commits - autogen.sh
configure.ac libswfdec/js libswfdec/swfdec_debug.h
libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c
libswfdec/swfdec_js_movie.c libswfdec/swfdec_movie.c
libswfdec/swfdec_movie.h libswfdec/swfdec_script.c
player/.gitignore player/Makefile.am
player/swfdec_playback_alsa.c player/swfdec_playback.c
player/swfdec_playback_none.c test/trace
Benjamin Otte
company at kemper.freedesktop.org
Wed Jan 31 07:27:38 PST 2007
autogen.sh | 2
configure.ac | 39 +++
libswfdec/js/jsfun.c | 11 -
libswfdec/js/jsinterp.c | 5
libswfdec/js/jsobj.c | 2
libswfdec/swfdec_debug.h | 2
libswfdec/swfdec_js.c | 4
libswfdec/swfdec_js_color.c | 33 +--
libswfdec/swfdec_js_movie.c | 25 --
libswfdec/swfdec_movie.c | 24 ++
libswfdec/swfdec_movie.h | 1
libswfdec/swfdec_script.c | 436 +++++++++++++++++++++++++++++++++++++----
player/.gitignore | 1
player/Makefile.am | 28 +-
player/swfdec_playback_none.c | 38 +++
test/trace/Makefile.am | 6
test/trace/color-new.swf |binary
test/trace/color-new.swf.trace | 10
test/trace/function1.swf |binary
test/trace/function1.swf.trace | 50 ++++
test/trace/function2.swf |binary
test/trace/function2.swf.trace | 2
22 files changed, 621 insertions(+), 98 deletions(-)
New commits:
diff-tree 9335e136a9a1f2f3dbbbda7a7b156b55d94e7c4c (from 90bd9323aab5388329dfac37a165bd421818875c)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 16:28:09 2007 +0100
handle colors not referring to movies
This also fixes the color-new test
diff --git a/libswfdec/swfdec_js_color.c b/libswfdec/swfdec_js_color.c
index ade8d6a..095abd7 100644
--- a/libswfdec/swfdec_js_color.c
+++ b/libswfdec/swfdec_js_color.c
@@ -32,7 +32,8 @@ swfdec_js_color_get_rgb (JSContext *cx,
int result;
SwfdecMovie *movie = JS_GetPrivate (cx, obj);
- g_assert (movie);
+ if (!movie)
+ return JS_TRUE;
result = (movie->color_transform.rb << 16) |
((movie->color_transform.gb % 256) << 8) |
(movie->color_transform.bb % 256);
@@ -55,7 +56,8 @@ swfdec_js_color_get_transform (JSContext
JSObject *ret;
SwfdecMovie *movie = JS_GetPrivate (cx, obj);
- g_assert (movie);
+ if (!movie)
+ return JS_TRUE;
ret = JS_NewObject (cx, NULL, NULL, NULL);
if (ret == NULL)
return JS_TRUE;
@@ -78,7 +80,8 @@ swfdec_js_color_set_rgb (JSContext *cx,
unsigned int color;
SwfdecMovie *movie = JS_GetPrivate (cx, obj);
- g_assert (movie);
+ if (!movie)
+ return JS_TRUE;
if (!JS_ValueToECMAUint32 (cx, argv[0], &color))
return JS_TRUE;
@@ -117,8 +120,9 @@ swfdec_js_color_set_transform (JSContext
JSObject *parse;
SwfdecMovie *movie = JS_GetPrivate (cx, obj);
- g_assert (movie);
- if (!JSVAL_IS_OBJECT (argv[0]))
+ if (!movie)
+ return JS_TRUE;
+ if (!movie)
return JS_TRUE;
parse = JSVAL_TO_OBJECT (argv[0]);
parse_property (cx, parse, "ra", &movie->color_transform.ra, TRUE);
@@ -161,7 +165,6 @@ swfdec_js_color_finalize (JSContext *cx,
SwfdecMovie *movie;
movie = JS_GetPrivate (cx, obj);
- /* since we also finalize the class, not everyone has a private object */
if (movie) {
g_object_unref (movie);
}
@@ -179,14 +182,16 @@ swfdec_js_color_new (JSContext *cx, JSOb
{
SwfdecMovie *movie;
- movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE);
- if (movie == NULL) {
- SWFDEC_INFO ("attempted to construct a color without a movie");
- return JS_TRUE;
+ if (argc > 0) {
+ movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE);
+ } else {
+ movie = NULL;
+ }
+ if (movie != NULL) {
+ if (!JS_SetPrivate (cx, obj, movie))
+ return JS_FALSE;
+ g_object_ref (movie);
}
- if (!JS_SetPrivate (cx, obj, movie))
- return JS_TRUE;
- g_object_ref (movie);
*rval = OBJECT_TO_JSVAL (obj);
return JS_TRUE;
}
@@ -195,7 +200,7 @@ void
swfdec_js_add_color (SwfdecPlayer *player)
{
JS_InitClass (player->jscx, player->jsobj, NULL,
- &color_class, swfdec_js_color_new, 1, NULL, color_methods,
+ &color_class, swfdec_js_color_new, 0, NULL, color_methods,
NULL, NULL);
}
diff-tree 90bd9323aab5388329dfac37a165bd421818875c (from 97a972c232892d919de3045f69e6fc3fac4b8ad3)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 16:27:20 2007 +0100
add print function for SetTarget
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index 9921af8..7c24b10 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -1407,6 +1407,15 @@ swfdec_action_target_path (JSContext *cx
/*** PRINT FUNCTIONS ***/
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;
@@ -1733,7 +1742,7 @@ static const SwfdecActionSpec actions[25
[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", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } },
+ [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", NULL },
diff-tree 97a972c232892d919de3045f69e6fc3fac4b8ad3 (from 4b0e92902dcfd08e55f34d6d56aecb10efac9314)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 16:26:51 2007 +0100
make eval (obj, "") return obj and not undefined
diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c
index 829c1ad..4c14100 100644
--- a/libswfdec/swfdec_js.c
+++ b/libswfdec/swfdec_js.c
@@ -343,7 +343,7 @@ static gboolean
swfdec_js_eval_internal (JSContext *cx, JSObject *obj, const char *str,
jsval *val, gboolean set)
{
- jsval cur = JSVAL_NULL;
+ jsval cur;
char *work = NULL;
SWFDEC_LOG ("eval called with \"%s\" on %p", str, obj);
@@ -358,8 +358,8 @@ swfdec_js_eval_internal (JSContext *cx,
if (cx->fp == NULL)
goto out;
obj = cx->fp->thisp;
- cur = OBJECT_TO_JSVAL (obj);
}
+ cur = OBJECT_TO_JSVAL (obj);
while (str != NULL && *str != '\0') {
char *dot = strchr (str, '.');
if (!JSVAL_IS_OBJECT (cur))
diff-tree 4b0e92902dcfd08e55f34d6d56aecb10efac9314 (from 29607ca556843663468425ffad907e69839a0d8f)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 16:26:04 2007 +0100
add test for Color constructor
diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 443cba2..27f0cac 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -16,6 +16,8 @@ EXTRA_DIST = \
children.swf.trace \
color-getters.swf \
color-getters.swf.trace \
+ color-new.swf \
+ color-new.swf.trace \
color-setRGB.swf \
color-setRGB.swf.trace \
color-setTransform-alpha.swf \
diff --git a/test/trace/color-new.swf b/test/trace/color-new.swf
new file mode 100755
index 0000000..e9f9727
Binary files /dev/null and b/test/trace/color-new.swf differ
diff --git a/test/trace/color-new.swf.trace b/test/trace/color-new.swf.trace
new file mode 100755
index 0000000..eb220d7
--- /dev/null
+++ b/test/trace/color-new.swf.trace
@@ -0,0 +1,10 @@
+test behaviour of Color when created without a movie
+[object Object]
+undefined
+undefined
+[object Object]
+undefined
+undefined
+[object Object]
+undefined
+undefined
diff-tree 29607ca556843663468425ffad907e69839a0d8f (from 62447e55d8fb4b74154694683d47070cd49e9868)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 14:50:27 2007 +0100
implement NextFrame, PreviousFrame, ToInteger, TargetPath, GotoLabel, GotoFrame2
Those are the actions needed by South Park studio
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index b172ec6..9921af8 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -35,6 +35,8 @@
#include "swfdec_movie.h"
#include "swfdec_player_internal.h"
#include "swfdec_root_movie.h"
+#include "swfdec_sprite.h"
+#include "swfdec_sprite_movie.h"
#include "js/jsfun.h"
#include "js/jsscope.h"
@@ -115,6 +117,25 @@ swfdec_action_push_string (JSContext *cx
return JS_TRUE;
}
+static double
+swfdec_action_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 isnan (d) ? 0 : d;
+ } else {
+ return 0;
+ }
+}
+
/*** ALL THE ACTION IS HERE ***/
static JSBool
@@ -140,6 +161,38 @@ swfdec_action_play (JSContext *cx, guint
}
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);
@@ -160,6 +213,76 @@ swfdec_action_goto_frame (JSContext *cx,
}
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 JSBool
+swfdec_action_goto_frame2 (JSContext *cx, guint action, const guint8 *data, guint len)
+{
+ SwfdecBits bits;
+ guint bias;
+ gboolean play;
+ jsval val;
+ int frame;
+ 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--;
+ if (JSVAL_IS_STRING (val)) {
+ const char *name = swfdec_js_to_string (cx, val);
+ if (name == NULL)
+ return JS_FALSE;
+ if (strchr (name, ':')) {
+ SWFDEC_ERROR ("FIXME: handle targets");
+ }
+ frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name);
+ if (frame == -1)
+ return JS_TRUE;
+ } else {
+ /* FIXME: how do we treat undefined etc? */
+ frame = swfdec_action_to_number (cx, val);
+ }
+ frame += bias;
+ /* now set it */
+ movie = swfdec_action_get_target (cx);
+ if (movie) {
+ 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 JSBool
swfdec_action_wait_for_frame (JSContext *cx, guint action, const guint8 *data, guint len)
{
SwfdecMovie *movie = swfdec_action_get_target (cx);
@@ -551,25 +674,6 @@ out:
return JS_TRUE;
}
-static double
-swfdec_action_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 isnan (d) ? 0 : d;
- } else {
- return 0;
- }
-}
-
static JSBool
swfdec_action_binary (JSContext *cx, guint action, const guint8 *data, guint len)
{
@@ -1274,6 +1378,32 @@ swfdec_action_shift (JSContext *cx, guin
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_action_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;
+}
+
/*** PRINT FUNCTIONS ***/
static char *
@@ -1431,6 +1561,26 @@ swfdec_action_print_constant_pool (guint
}
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;
@@ -1443,6 +1593,17 @@ swfdec_action_print_goto_frame (guint ac
}
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;
@@ -1474,8 +1635,8 @@ typedef struct {
static const SwfdecActionSpec actions[256] = {
/* version 3 */
- [0x04] = { "NextFrame", NULL },
- [0x05] = { "PreviousFrame", NULL },
+ [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 },
@@ -1494,10 +1655,10 @@ static const SwfdecActionSpec actions[25
[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 },
+ [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] = { "SetTarget22", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } },
+ [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 } },
@@ -1532,7 +1693,7 @@ static const SwfdecActionSpec actions[25
[0x42] = { "InitArray", NULL },
[0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } },
[0x44] = { "Typeof", NULL },
- [0x45] = { "TargetPath", NULL },
+ [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 } },
@@ -1573,7 +1734,7 @@ static const SwfdecActionSpec actions[25
/* 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", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } },
- [0x8c] = { "GotoLabel", NULL },
+ [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", NULL },
/* version 7 */
@@ -1590,7 +1751,7 @@ static const SwfdecActionSpec actions[25
/* 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", 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 } }
};
char *
diff-tree 62447e55d8fb4b74154694683d47070cd49e9868 (from 75e9e227691415642b037d6be0ff7c2ccc90772c)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 14:48:56 2007 +0100
add swfdec_movie_get_path
The function returns the "path" as used in ActionScript
diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c
index 70ddece..d33ba94 100644
--- a/libswfdec/swfdec_js_movie.c
+++ b/libswfdec/swfdec_js_movie.c
@@ -464,36 +464,19 @@ swfdec_js_getURL (JSContext *cx, JSObjec
return JS_TRUE;
}
-static GString *
-get_name (SwfdecMovie *movie)
-{
- GString *s;
-
- if (movie->parent) {
- s = get_name (movie->parent);
- g_string_append_c (s, '.');
- g_string_append (s, movie->name);
- } else {
- /* the name can be changed */
- s = g_string_new ("_level");
- g_string_append_printf (s, "%u", movie->depth + 16384);
- }
- return s;
-}
-
static JSBool
swfdec_js_movie_to_string (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
- GString *s;
+ char *s;
JSString *string;
SwfdecMovie *movie;
movie = JS_GetPrivate (cx, obj);
g_assert (movie);
- s = get_name (movie);
- string = JS_NewStringCopyZ (cx, s->str);
- g_string_free (s, TRUE);
+ s = swfdec_movie_get_path (movie);
+ string = JS_NewStringCopyZ (cx, s);
+ g_free (s);
if (string == NULL)
return JS_FALSE;
*rval = STRING_TO_JSVAL (string);
diff --git a/libswfdec/swfdec_movie.c b/libswfdec/swfdec_movie.c
index a851cd2..3ab9c88 100644
--- a/libswfdec/swfdec_movie.c
+++ b/libswfdec/swfdec_movie.c
@@ -787,6 +787,30 @@ swfdec_movie_goto (SwfdecMovie *movie, g
klass->goto_frame (movie, frame);
}
+char *
+swfdec_movie_get_path (SwfdecMovie *movie)
+{
+ GString *s;
+
+ g_return_val_if_fail (SWFDEC_IS_MOVIE (movie), NULL);
+
+ s = g_string_new ("");
+ do {
+ if (movie->parent) {
+ g_string_prepend (s, movie->name);
+ g_string_prepend_c (s, '.');
+ } else {
+ char *ret = g_strdup_printf ("_level%u%s",
+ movie->depth + 16384, s->str);
+ g_string_free (s, TRUE);
+ return ret;
+ }
+ movie = movie->parent;
+ } while (TRUE);
+ g_assert_not_reached ();
+ return NULL;
+}
+
int
swfdec_movie_compare_depths (gconstpointer a, gconstpointer b)
{
diff --git a/libswfdec/swfdec_movie.h b/libswfdec/swfdec_movie.h
index 61f495c..0351b54 100644
--- a/libswfdec/swfdec_movie.h
+++ b/libswfdec/swfdec_movie.h
@@ -177,6 +177,7 @@ void swfdec_movie_send_mouse_change (Sw
SwfdecMovie * swfdec_movie_get_movie_at (SwfdecMovie * movie,
double x,
double y);
+char * swfdec_movie_get_path (SwfdecMovie * movie);
void swfdec_movie_render (SwfdecMovie * movie,
cairo_t * cr,
const SwfdecColorTransform *trans,
diff-tree 75e9e227691415642b037d6be0ff7c2ccc90772c (from ae5cb38d44ea9dabd46c38fd5231ef3afcfd86ac)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 10:32:33 2007 +0100
add 2 tests for DefineFunction
diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 635e098..443cba2 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -42,6 +42,10 @@ EXTRA_DIST = \
currentframe.swf.trace \
double.swf \
double.swf.trace \
+ function1.swf \
+ function1.swf.trace \
+ function2.swf \
+ function2.swf.trace \
goto1.swf \
goto1.swf.trace \
goto2.swf \
diff --git a/test/trace/function1.swf b/test/trace/function1.swf
new file mode 100755
index 0000000..63f85d4
Binary files /dev/null and b/test/trace/function1.swf differ
diff --git a/test/trace/function1.swf.trace b/test/trace/function1.swf.trace
new file mode 100755
index 0000000..8403c7e
--- /dev/null
+++ b/test/trace/function1.swf.trace
@@ -0,0 +1,50 @@
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
+undefined
+0
+_level0
+1
+_level0
diff --git a/test/trace/function2.swf b/test/trace/function2.swf
new file mode 100755
index 0000000..23a6b46
Binary files /dev/null and b/test/trace/function2.swf differ
diff --git a/test/trace/function2.swf.trace b/test/trace/function2.swf.trace
new file mode 100755
index 0000000..59c46d4
--- /dev/null
+++ b/test/trace/function2.swf.trace
@@ -0,0 +1,2 @@
+[type Function]
+3
diff-tree ae5cb38d44ea9dabd46c38fd5231ef3afcfd86ac (from e2aa7731c273e897af818cadf20d5bb923d8c01e)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 10:30:41 2007 +0100
implement CallFunction, BitRShift, BitLShift and BitURShift
includes some fixes like implementing the function with name case
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index c398e62..b172ec6 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -387,6 +387,33 @@ swfdec_action_call (JSContext *cx, guint
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;
+ jsval fun;
+
+ 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 (n_args + 2 > (guint) (fp->sp - fp->spbase))
+ return JS_FALSE;
+
+ obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain);
+ if (!JS_GetProperty (cx, obj, s, &fun))
+ return JS_FALSE;
+ 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)
{
@@ -1207,7 +1234,9 @@ swfdec_action_define_function (JSContext
}
*cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object);
} else {
- SWFDEC_ERROR ("FIXME: implement");
+ jsval val = OBJECT_TO_JSVAL (fun->object);
+ if (!JS_SetProperty (cx, OBJ_THIS_OBJECT (cx, cx->fp->scopeChain), function_name, &val))
+ return JS_FALSE;
}
/* update current context */
@@ -1215,6 +1244,36 @@ swfdec_action_define_function (JSContext
return JS_TRUE;
}
+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]);
+}
+
/*** PRINT FUNCTIONS ***/
static char *
@@ -1464,8 +1523,8 @@ static const SwfdecActionSpec actions[25
/* version 5 */
[0x3a] = { "Delete", NULL },
[0x3b] = { "Delete2", NULL },
- [0x3c] = { "DefineLocal", NULL },
- [0x3d] = { "CallFunction", NULL },
+ [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 },
[0x3f] = { "Modulo", NULL },
[0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } },
@@ -1495,9 +1554,9 @@ static const SwfdecActionSpec actions[25
[0x60] = { "BitAnd", NULL },
[0x61] = { "BitOr", NULL },
[0x62] = { "BitXor", NULL },
- [0x63] = { "BitLShift", NULL },
- [0x64] = { "BitRShift", NULL },
- [0x65] = { "BitURShift", NULL },
+ [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 } },
diff-tree e2aa7731c273e897af818cadf20d5bb923d8c01e (from ee7ecfa22195201642e114bfdb24d28aa690e00c)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 10:29:46 2007 +0100
create a call object for calls to SWF code
diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c
index 1d15966..ce8d014 100644
--- a/libswfdec/js/jsinterp.c
+++ b/libswfdec/js/jsinterp.c
@@ -963,7 +963,10 @@ have_fun:
}
ok = js_Interpret(cx, &v);
} else if (swf) {
- frame.scopeChain = funobj; /* FIXME */
+ if (!js_GetCallObject(cx, &frame, parent)) {
+ ok = JS_FALSE;
+ goto out;
+ }
ok = swfdec_script_interpret(swf, cx, &v);
} else {
/* fun might be onerror trying to report a syntax error in itself. */
diff-tree ee7ecfa22195201642e114bfdb24d28aa690e00c (from 56d6b7a99657f96cc093d7136ff7eea4a6acfcfd)
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Jan 31 10:28:46 2007 +0100
return "[type Function]" from function.toString()
diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c
index 84121de..a085673 100644
--- a/libswfdec/js/jsfun.c
+++ b/libswfdec/js/jsfun.c
@@ -1418,7 +1418,12 @@ js_fun_toString(JSContext *cx, JSObject
static JSBool
fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
- return js_fun_toString(cx, obj, 0, argc, argv, rval);
+ JSString *string = JS_InternString (cx, "[type Function]");
+
+ if (string == NULL)
+ return JS_FALSE;
+ *rval = STRING_TO_JSVAL (string);
+ return JS_TRUE;
}
#if JS_HAS_TOSOURCE
diff-tree 56d6b7a99657f96cc093d7136ff7eea4a6acfcfd (from bd449d3ebe7adc1a6fc90beafef2f192a6c23ac4)
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Jan 30 14:54:17 2007 +0100
implement DefineFunction
contains some changes to script handling that are required to make this
work properly, like allowing scripts that don't end with a 0 action
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index e2ddcec..c398e62 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -36,6 +36,7 @@
#include "swfdec_player_internal.h"
#include "swfdec_root_movie.h"
#include "js/jsfun.h"
+#include "js/jsscope.h"
/*** CONSTANT POOLS ***/
@@ -1134,9 +1135,129 @@ swfdec_action_init_object (JSContext *cx
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;
+
+ 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");
+ return JS_FALSE;
+ }
+ n_args = swfdec_bits_get_u16 (&bits);
+ if (*function_name == '\0') {
+ /* anonymous function */
+ fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA, NULL, NULL);
+ } else {
+ /* named function */
+ fun = JS_NewFunction (cx, NULL, n_args, 0, NULL, function_name);
+ }
+ if (fun == NULL)
+ return JS_FALSE;
+ for (i = 0; i < n_args; i++) {
+ JSAtom *atom;
+ const char *arg_name = swfdec_bits_get_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;
+ }
+ }
+ size = swfdec_bits_get_u16 (&bits);
+ /* check the script can be created */
+ script = cx->fp->swf;
+ 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 */
+ SwfdecBuffer *buffer = swfdec_buffer_new_subbuffer (script->buffer,
+ cx->fp->pc + 3 + len - script->buffer->data, size);
+ swfdec_bits_init (&bits, buffer);
+ script = swfdec_script_new_for_player (JS_GetContextPrivate (cx),
+ &bits, *function_name ? function_name : "<lambda>",
+ ((SwfdecScript *) cx->fp->swf)->version);
+ swfdec_buffer_unref (buffer);
+ }
+ if (script == NULL) {
+ SWFDEC_ERROR ("failed to create script");
+ return JS_FALSE;
+ }
+ fun->swf = script;
+ /* attach the function */
+ if (*function_name == '\0') {
+ if (action == 0) {
+ SWFDEC_ERROR ("not enough stack space available");
+ return JS_FALSE;
+ }
+ *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object);
+ } else {
+ SWFDEC_ERROR ("FIXME: implement");
+ }
+
+ /* update current context */
+ cx->fp->pc += 3 + len + size;
+ return JS_TRUE;
+}
+
/*** PRINT FUNCTIONS ***/
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;
+
+ string = g_string_new ("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, '(');
+
+ for (i = 0; i < n_args; i++) {
+ const char *arg_name = swfdec_bits_get_string (&bits);
+ if (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, ", ");
+ 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_url (guint action, const guint8 *data, guint len)
{
SwfdecBits bits;
@@ -1406,7 +1527,7 @@ static const SwfdecActionSpec actions[25
[0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } },
[0x9a] = { "GetURL2", NULL },
/* version 5 */
- [0x9b] = { "DefineFunction", NULL },
+ [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 },
@@ -1442,7 +1563,7 @@ swfdec_script_foreach_internal (SwfdecBi
gconstpointer bytecode;
bytecode = bits->ptr;
- while ((action = swfdec_bits_get_u8 (bits))) {
+ while (swfdec_bits_left (bits) && (action = swfdec_bits_get_u8 (bits))) {
if (action & 0x80) {
len = swfdec_bits_get_u16 (bits);
data = bits->ptr;
@@ -1634,8 +1755,10 @@ swfdec_script_interpret (SwfdecScript *s
while (TRUE) {
/* check pc */
+ if (pc == endpc) /* needed for scripts created via DefineFunction */
+ break;
if (pc < startpc || pc >= endpc) {
- SWFDEC_ERROR ("pc %p not in valid range [%p, %p] anymore", pc, startpc, endpc);
+ SWFDEC_ERROR ("pc %p not in valid range [%p, %p) anymore", pc, startpc, endpc);
goto internal_error;
}
diff-tree bd449d3ebe7adc1a6fc90beafef2f192a6c23ac4 (from 2ae8e627b6ad7d5c5cba649db11cde9758e43815)
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Jan 30 14:52:20 2007 +0100
fix SwfdecScript reference handling
- intitialize fun->swf to NULL
- unref fun->swf on finalization
diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c
index 1ba58f8..84121de 100644
--- a/libswfdec/js/jsfun.c
+++ b/libswfdec/js/jsfun.c
@@ -1042,6 +1042,7 @@ fun_convert(JSContext *cx, JSObject *obj
}
}
+extern void swfdec_script_unref (void *script);
static void
fun_finalize(JSContext *cx, JSObject *obj)
{
@@ -1058,6 +1059,8 @@ fun_finalize(JSContext *cx, JSObject *ob
return;
if (fun->script)
js_DestroyScript(cx, fun->script);
+ if (fun->swf)
+ swfdec_script_unref (fun->swf);
JS_free(cx, fun);
}
@@ -1928,6 +1931,7 @@ js_NewFunction(JSContext *cx, JSObject *
fun->object = NULL;
fun->native = native;
fun->script = NULL;
+ fun->swf = NULL;
fun->nargs = nargs;
fun->extra = 0;
fun->nvars = 0;
diff-tree 2ae8e627b6ad7d5c5cba649db11cde9758e43815 (from 7b858d98456af8c801b9c346ef7abc8ebd4a0453)
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Jan 30 12:38:28 2007 +0100
check !JSVAL_IS_NULL in all JSVAL_IS_OBJECT checks
diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c
index 64f0746..e2ddcec 100644
--- a/libswfdec/swfdec_script.c
+++ b/libswfdec/swfdec_script.c
@@ -403,7 +403,7 @@ swfdec_action_call_method (JSContext *cx
if (n_args + 3 > (guint) (fp->sp - fp->spbase))
return JS_FALSE;
- if (!JSVAL_IS_OBJECT (fp->sp[-2]))
+ if (!JSVAL_IS_OBJECT (fp->sp[-2]) || JSVAL_IS_NULL (fp->sp[-2]))
goto fail;
obj = JSVAL_TO_OBJECT (fp->sp[-2]);
if (s[0] == '\0') {
@@ -689,7 +689,7 @@ swfdec_action_get_member (JSContext *cx,
if (s == NULL)
return JS_FALSE;
- if (JSVAL_IS_OBJECT (cx->fp->sp[-2])) {
+ if (JSVAL_IS_OBJECT (cx->fp->sp[-2]) && !JSVAL_IS_NULL (cx->fp->sp[-2])) {
if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-2]), s, &cx->fp->sp[-2]))
return JS_FALSE;
} else {
@@ -708,7 +708,7 @@ swfdec_action_set_member (JSContext *cx,
if (s == NULL)
return JS_FALSE;
- if (JSVAL_IS_OBJECT (cx->fp->sp[-3])) {
+ 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;
}
@@ -989,7 +989,7 @@ swfdec_action_set_target (JSContext *cx,
}
/* evaluate relative to this to not get trapped by previous SetTarget calls */
target = swfdec_js_eval (cx, cx->fp->thisp, (const char *) data);
- if (!JSVAL_IS_OBJECT (target)) {
+ if (!JSVAL_IS_OBJECT (target) || JSVAL_IS_NULL (target)) {
SWFDEC_WARNING ("target is not an object");
return JS_TRUE;
}
@@ -1003,7 +1003,7 @@ swfdec_action_set_target2 (JSContext *cx
val = cx->fp->sp[-1];
cx->fp->sp--;
- if (!JSVAL_IS_OBJECT (val)) {
+ if (!JSVAL_IS_OBJECT (val) || JSVAL_IS_NULL (val)) {
SWFDEC_WARNING ("target is not an object");
return JS_TRUE;
}
@@ -1034,7 +1034,7 @@ swfdec_action_start_drag (JSContext *cx,
fp->sp[-6] = fp->sp[-5];
fp->sp[-5] = tmp;
}
- if (!JSVAL_IS_OBJECT (fp->sp[-1])) {
+ if (!JSVAL_IS_OBJECT (fp->sp[-1]) || JSVAL_IS_NULL (fp->sp[-1])) {
fp->sp -= n_args + 2;
return JS_TRUE;
}
@@ -1084,7 +1084,7 @@ swfdec_action_new_object (JSContext *cx,
}
fp->sp[-1] = constructor;
- if (!JSVAL_IS_OBJECT (constructor))
+ if (!JSVAL_IS_OBJECT (constructor) || JSVAL_IS_NULL (constructor))
goto fail;
object = JSVAL_TO_OBJECT (constructor);
if (JS_GetClass (object) != &js_FunctionClass)
diff-tree 7b858d98456af8c801b9c346ef7abc8ebd4a0453 (from abfaad4612d9129e2cf0de1402f623e22d356831)
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Jan 30 12:34:20 2007 +0100
catch a case where fun->script is accessed unconditionally
diff --git a/libswfdec/js/jsobj.c b/libswfdec/js/jsobj.c
index 2033c97..112bdc8 100644
--- a/libswfdec/js/jsobj.c
+++ b/libswfdec/js/jsobj.c
@@ -2356,6 +2356,8 @@ Detecting(JSContext *cx, jsbytecode *pc)
JSAtom *atom;
script = cx->fp->script;
+ if (script == NULL)
+ return JS_FALSE;
for (endpc = script->code + script->length; pc < endpc; pc++) {
/* General case: a branch or equality op follows the access. */
op = (JSOp) *pc;
diff-tree abfaad4612d9129e2cf0de1402f623e22d356831 (from parents)
Merge: d8b4748701572b483c96bbb4a66a6f026cd1c1d7 a7b8850adba4086c321e69c8933f6248b3de0803
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Jan 30 09:59:37 2007 +0100
Merge branch 'master' into interpreter
diff-tree a7b8850adba4086c321e69c8933f6248b3de0803 (from 133819a86a6435cce34751911118b74dd51f9bfc)
Author: Benjamin Otte <otte at gnome.org>
Date: Tue Jan 30 09:56:54 2007 +0100
add swfedit binary to gitignore
diff --git a/test/.gitignore b/test/.gitignore
index ef52ce4..9280a20 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -11,3 +11,4 @@ Makefile.in
dump
parse
swfdec-extract
+swfedit
diff-tree 133819a86a6435cce34751911118b74dd51f9bfc (from parents)
Merge: d3add5d691f7832d56e3126003ce242822bfe11d 4e7806e7020535920cbb2009ed8b039fd64c046c
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Jan 29 22:34:49 2007 +0100
Merge branch 'master' of ssh://company@git.freedesktop.org/git/swfdec
diff-tree d3add5d691f7832d56e3126003ce242822bfe11d (from f9f53b7a60b641e2ba5c846430f2fb48ac013eb0)
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Jan 29 22:33:27 2007 +0100
rework audio configuration subsystem
- make it easier to plug new backends
- add a "none" backend when alsa isn't available
diff --git a/configure.ac b/configure.ac
index eb69535..e02adfd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,13 +86,40 @@ if test "$HAVE_GTK" = "no"; then
fi
AM_CONDITIONAL(WITH_GTK,[test "$HAVE_GTK" != "no"])
-PKG_CHECK_MODULES(ALSA, alsa >= 1.0, HAVE_ALSA=yes, HAVE_ALSA=no)
-AC_SUBST(ALSA_LIBS)
-AC_SUBST(ALSA_CFLAGS)
-if test "$HAVE_ALSA" = "no"; then
- AC_MSG_WARN([cannot find alsa, player will be disabled])
+dnl
+dnl audio backend
+dnl
+AC_ARG_WITH(audio,
+ [AC_HELP_STRING([--with-audio=@<:@auto/alsa/none@:>@],
+ [audio backend to use])],,
+ [with_audio=auto])
+
+AUDIO_TYPE=
+if test "$with_audio" = "auto" -o "$with_audio" = "alsa"; then
+ PKG_CHECK_MODULES(ALSA, alsa >= 1.0, AUDIO_TYPE=alsa)
+ if test "$AUDIO_TYPE" = "alsa"; then
+ with_audio=alsa
+ else
+ AC_MSG_WARN([no alsa audio support])
+ fi
+ AUDIO_CFLAGS=$ALSA_CFLAGS
+ AUDIO_LIBS=$ALSA_LIBS
+fi
+
+if test "$with_audio" = "auto" -o "$with_audio" = "none"; then
+ AUDIO_CFLAGS=
+ AUDIO_LIBS=
+ AUDIO_TYPE=none
fi
-AM_CONDITIONAL(WITH_ALSA,[test "$HAVE_ALSA" != "no"])
+
+if test "x$AUDIO_TYPE" = "x"; then
+ AC_MSG_ERROR([desired audio support could not be used])
+else
+ AC_MSG_NOTICE([audio backend: $AUDIO_TYPE])
+fi
+AC_SUBST(AUDIO_LIBS)
+AC_SUBST(AUDIO_CFLAGS)
+AC_SUBST(AUDIO_TYPE)
PKG_CHECK_MODULES(LIBOIL, liboil-0.3 >= 0.3.1.1, HAVE_LIBOIL=yes, HAVE_LIBOIL=no)
AC_SUBST(LIBOIL_LIBS)
diff --git a/player/.gitignore b/player/.gitignore
index 3e3d43c..f2dfbf1 100644
--- a/player/.gitignore
+++ b/player/.gitignore
@@ -9,6 +9,7 @@ Makefile.in
*.o
*.lo
*.loT
+swfdec_playback.c
libswfdecui.la
swfdebug
diff --git a/player/Makefile.am b/player/Makefile.am
index 0a29cc5..c56ee91 100644
--- a/player/Makefile.am
+++ b/player/Makefile.am
@@ -1,5 +1,13 @@
if WITH_GTK
-if WITH_ALSA
+
+# this workaround is needed or autotools don't generate the .deps/*.Plo files correctly
+swfdec_playback.c: swfdec_playback_$(AUDIO_TYPE).c Makefile
+ cmp -s $(srcdir)/swfdec_playback_$(AUDIO_TYPE).c swfdec_playback.c \
+ || cp $(srcdir)/swfdec_playback_$(AUDIO_TYPE).c swfdec_playback.c
+
+BUILT_SOURCES = swfdec_playback.c
+CLEANFILES = swfdec_playback.c
+
noinst_LTLIBRARIES = libswfdecui.la
noinst_PROGRAMS = swfplay swfdebug
@@ -31,15 +39,17 @@ noinst_HEADERS = \
swfdec_slow_loader.h \
swfdec_widget.h
-libswfdecui_la_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS)
-libswfdecui_la_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS)
-swfplay_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS)
-swfplay_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS)
+libswfdecui_la_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(AUDIO_CFLAGS)
+libswfdecui_la_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(AUDIO_LIBS)
+swfplay_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS)
+swfplay_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS)
swfplay_LDADD = libswfdecui.la
-swfdebug_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
-swfdebug_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS)
+swfdebug_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
+swfdebug_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS)
swfdebug_LDADD = libswfdecui.la $(top_builddir)/libswfdec/js/libjs.la
endif
-endif
-EXTRA_DIST = swfdebug.c swfplay.c swfdec_widget.c swfdec_widget.h swfdec_playback.c swfdec_playback.h
+EXTRA_DIST = \
+ swfdec_playback_alsa.c \
+ swfdec_playback_none.c
+
diff --git a/player/swfdec_playback.c b/player/swfdec_playback.c
deleted file mode 100644
index ea47099..0000000
--- a/player/swfdec_playback.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <alsa/asoundlib.h>
-#include "swfdec_source.h"
-
-/* Why ALSA sucks for beginners:
- * - snd_pcm_delay is not sample-exact, but period-exact most of the time.
- * Yay for getting told the time every 512 samples when a human notices
- * a delay of 100 samples (oooops)
- * - lots of functions are simply not implemented. So the super-smart idea
- * of using snd_pcm_rewind to avoid XRUNS and still get low latency has
- * some issues when dmix just returns -EIO all of the time. That wouldn't
- * be so bad if there was actually a way to query if it's supported.
- * - But to make up for all this, you have 10 hardware parameters, 10
- * software parameters and 10 configuration parameters. All of this is
- * naturally supported on 10 driver APIs depending on kernel. So if your
- * sound card seems to do weird stuff, that is not my fault.
- * Welcome to Linux sound in the 21st century.
- */
-
-/*** DEFINITIONS ***/
-
-typedef struct {
- SwfdecPlayer * player;
- GList * streams; /* all Stream objects */
- GMainContext * context; /* context we work in */
-} Sound;
-
-typedef struct {
- Sound * sound; /* reference to sound object */
- SwfdecAudio * audio; /* the audio we play back */
- snd_pcm_t * pcm; /* the pcm we play back to */
- GSource ** sources; /* sources for writing data */
- guint n_sources; /* number of sources */
- guint offset; /* offset into sound */
-} Stream;
-
-#define ALSA_TRY(func,msg) G_STMT_START{ \
- int err = func; \
- if (err < 0) \
- g_printerr (msg ": %s\n", snd_strerror (err)); \
-}G_STMT_END
-
-#define ALSA_ERROR(func,msg,retval) G_STMT_START { \
- int err = func; \
- if (err < 0) { \
- g_printerr (msg ": %s\n", snd_strerror (err)); \
- return retval; \
- } \
-}G_STMT_END
-
-/*** STREAMS ***/
-
-static snd_pcm_uframes_t
-write_player (Stream *stream, const snd_pcm_channel_area_t *dst,
- snd_pcm_uframes_t offset, snd_pcm_uframes_t avail)
-{
- /* FIXME: do a long path if this doesn't hold */
- g_assert (dst[1].first - dst[0].first == 16);
- g_assert (dst[0].addr == dst[1].addr);
- g_assert (dst[0].step == dst[1].step);
- g_assert (dst[0].step == 32);
-
- memset (dst[0].addr + offset * dst[0].step / 8, 0, avail * 4);
- swfdec_audio_render (stream->audio, dst[0].addr + offset * dst[0].step / 8,
- stream->offset, avail);
- //g_print ("rendering %u %u\n", stream->offset, (guint) avail);
- return avail;
-}
-
-static gboolean
-try_write (Stream *stream)
-{
- snd_pcm_sframes_t avail_result;
- snd_pcm_uframes_t offset, avail;
- const snd_pcm_channel_area_t *dst;
-
- while (TRUE) {
- avail_result = snd_pcm_avail_update (stream->pcm);
- ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE);
- if (avail_result == 0)
- return TRUE;
- avail = avail_result;
- ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail),
- "snd_pcm_mmap_begin failed", FALSE);
- //g_print (" avail = %u\n", (guint) avail);
-
- avail = write_player (stream, dst, offset, avail);
- if (snd_pcm_mmap_commit (stream->pcm, offset, avail) < 0) {
- g_printerr ("snd_pcm_mmap_commit failed\n");
- return FALSE;
- }
- stream->offset += avail;
- //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail);
- }
- return TRUE;
-}
-
-static void
-swfdec_stream_remove_handlers (Stream *stream)
-{
- unsigned int i;
-
- for (i = 0; i < stream->n_sources; i++) {
- if (stream->sources[i]) {
- g_source_destroy (stream->sources[i]);
- g_source_unref (stream->sources[i]);
- stream->sources[i] = NULL;
- }
- }
-}
-
-static void swfdec_stream_start (Stream *stream);
-static gboolean
-handle_stream (GIOChannel *source, GIOCondition cond, gpointer data)
-{
- Stream *stream = data;
- snd_pcm_state_t state;
-
- state = snd_pcm_state (stream->pcm);
- if (state != SND_PCM_STATE_RUNNING) {
- swfdec_stream_start (stream);
- } else {
- try_write (stream);
- }
- return TRUE;
-}
-
-static void
-swfdec_stream_install_handlers (Stream *stream)
-{
- if (stream->n_sources > 0) {
- struct pollfd polls[stream->n_sources];
- unsigned int i, count;
- if (stream->n_sources > 1)
- g_printerr ("attention: more than one fd!\n");
- count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources);
- for (i = 0; i < count; i++) {
- if (stream->sources[i] != NULL)
- continue;
- GIOChannel *channel = g_io_channel_unix_new (polls[i].fd);
- stream->sources[i] = g_io_create_watch (channel, polls[i].events);
- g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH);
- g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL);
- g_io_channel_unref (channel);
- g_source_attach (stream->sources[i], stream->sound->context);
- }
- }
-}
-
-static void
-swfdec_stream_start (Stream *stream)
-{
- snd_pcm_state_t state = snd_pcm_state (stream->pcm);
- switch (state) {
- case SND_PCM_STATE_XRUN:
- ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",);
- //g_print ("XRUN!\n");
- /* fall through */
- case SND_PCM_STATE_SUSPENDED:
- case SND_PCM_STATE_PREPARED:
- stream->offset = 0;
- //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay);
- if (try_write (stream)) {
- ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",);
- swfdec_stream_install_handlers (stream);
- }
- break;
- default:
- break;
- }
-}
-
-static void
-swfdec_stream_open (Sound *sound, SwfdecAudio *audio)
-{
- Stream *stream;
- snd_pcm_t *ret;
- snd_pcm_hw_params_t *hw_params;
- unsigned int rate;
- snd_pcm_uframes_t uframes;
-
- /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */
- ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK),
- "Failed to open sound device", );
-
- snd_pcm_hw_params_alloca (&hw_params);
- if (snd_pcm_hw_params_any (ret, hw_params) < 0) {
- g_printerr ("No sound format available\n");
- return;
- }
- if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
- g_printerr ("Failed setting access\n");
- goto fail;
- }
- if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) {
- g_printerr ("Failed setting format\n");
- goto fail;
- }
- if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) {
- g_printerr ("Failed setting channels\n");
- goto fail;
- }
- rate = 44100;
- if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) {
- g_printerr ("Failed setting rate\n");
- goto fail;
- }
- uframes = 16384;
- if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) {
- g_printerr ("Failed setting buffer size\n");
- goto fail;
- }
- if (snd_pcm_hw_params (ret, hw_params) < 0) {
- g_printerr ("Could not set hardware parameters\n");
- goto fail;
- }
-#if 0
- {
- snd_output_t *log;
- snd_output_stdio_attach (&log, stderr, 0);
- snd_pcm_hw_params_dump (hw_params, log);
- }
-#endif
- stream = g_new0 (Stream, 1);
- stream->sound = sound;
- stream->audio = g_object_ref (audio);
- stream->pcm = ret;
- stream->n_sources = snd_pcm_poll_descriptors_count (ret);
- if (stream->n_sources > 0)
- stream->sources = g_new0 (GSource *, stream->n_sources);
- sound->streams = g_list_prepend (sound->streams, stream);
- swfdec_stream_start (stream);
- return;
-
-fail:
- snd_pcm_close (ret);
-}
-
-static void
-swfdec_stream_close (Stream *stream)
-{
- ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing");
- swfdec_stream_remove_handlers (stream);
- g_free (stream->sources);
- stream->sound->streams = g_list_remove (stream->sound->streams, stream);
- g_object_unref (stream->audio);
- g_free (stream);
-}
-
-/*** SOUND ***/
-
-static void
-advance_before (SwfdecPlayer *player, guint msecs, guint audio_samples, gpointer data)
-{
- Sound *sound = data;
- GList *walk;
-
- for (walk = sound->streams; walk; walk = walk->next) {
- Stream *stream = walk->data;
- if (audio_samples >= stream->offset) {
- stream->offset = 0;
- } else {
- stream->offset -= audio_samples;
- }
- }
-}
-
-static void
-audio_added (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound)
-{
- swfdec_stream_open (sound, audio);
-}
-
-static void
-audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound)
-{
- GList *walk;
-
- for (walk = sound->streams; walk; walk = walk->next) {
- Stream *stream = walk->data;
- if (stream->audio == audio) {
- swfdec_stream_close (stream);
- return;
- }
- }
- g_assert_not_reached ();
-}
-
-gpointer
-swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
-{
- Sound *sound;
- const GList *walk;
-
- g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
- g_return_val_if_fail (context != NULL, NULL);
-
- sound = g_new0 (Sound, 1);
- sound->player = g_object_ref (player);
- g_signal_connect (player, "advance", G_CALLBACK (advance_before), sound);
- g_signal_connect (player, "audio-added", G_CALLBACK (audio_added), sound);
- g_signal_connect (player, "audio-removed", G_CALLBACK (audio_removed), sound);
- for (walk = swfdec_player_get_audio (player); walk; walk = walk->next) {
- swfdec_stream_open (sound, walk->data);
- }
- g_main_context_ref (context);
- sound->context = context;
- return sound;
-}
-
-void
-swfdec_playback_close (gpointer data)
-{
- Sound *sound = data;
-#define REMOVE_HANDLER_FULL(obj,func,data,count) G_STMT_START {\
- if (g_signal_handlers_disconnect_by_func ((obj), \
- G_CALLBACK (func), (data)) != (count)) { \
- g_assert_not_reached (); \
- } \
-} G_STMT_END
-#define REMOVE_HANDLER(obj,func,data) REMOVE_HANDLER_FULL (obj, func, data, 1)
-
- while (sound->streams)
- swfdec_stream_close (sound->streams->data);
- REMOVE_HANDLER (sound->player, advance_before, sound);
- REMOVE_HANDLER (sound->player, audio_added, sound);
- REMOVE_HANDLER (sound->player, audio_removed, sound);
- g_object_unref (sound->player);
- g_main_context_unref (sound->context);
- g_free (sound);
-}
-
-
diff --git a/player/swfdec_playback_alsa.c b/player/swfdec_playback_alsa.c
new file mode 100644
index 0000000..ea47099
--- /dev/null
+++ b/player/swfdec_playback_alsa.c
@@ -0,0 +1,355 @@
+/* Swfdec
+ * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <alsa/asoundlib.h>
+#include "swfdec_source.h"
+
+/* Why ALSA sucks for beginners:
+ * - snd_pcm_delay is not sample-exact, but period-exact most of the time.
+ * Yay for getting told the time every 512 samples when a human notices
+ * a delay of 100 samples (oooops)
+ * - lots of functions are simply not implemented. So the super-smart idea
+ * of using snd_pcm_rewind to avoid XRUNS and still get low latency has
+ * some issues when dmix just returns -EIO all of the time. That wouldn't
+ * be so bad if there was actually a way to query if it's supported.
+ * - But to make up for all this, you have 10 hardware parameters, 10
+ * software parameters and 10 configuration parameters. All of this is
+ * naturally supported on 10 driver APIs depending on kernel. So if your
+ * sound card seems to do weird stuff, that is not my fault.
+ * Welcome to Linux sound in the 21st century.
+ */
+
+/*** DEFINITIONS ***/
+
+typedef struct {
+ SwfdecPlayer * player;
+ GList * streams; /* all Stream objects */
+ GMainContext * context; /* context we work in */
+} Sound;
+
+typedef struct {
+ Sound * sound; /* reference to sound object */
+ SwfdecAudio * audio; /* the audio we play back */
+ snd_pcm_t * pcm; /* the pcm we play back to */
+ GSource ** sources; /* sources for writing data */
+ guint n_sources; /* number of sources */
+ guint offset; /* offset into sound */
+} Stream;
+
+#define ALSA_TRY(func,msg) G_STMT_START{ \
+ int err = func; \
+ if (err < 0) \
+ g_printerr (msg ": %s\n", snd_strerror (err)); \
+}G_STMT_END
+
+#define ALSA_ERROR(func,msg,retval) G_STMT_START { \
+ int err = func; \
+ if (err < 0) { \
+ g_printerr (msg ": %s\n", snd_strerror (err)); \
+ return retval; \
+ } \
+}G_STMT_END
+
+/*** STREAMS ***/
+
+static snd_pcm_uframes_t
+write_player (Stream *stream, const snd_pcm_channel_area_t *dst,
+ snd_pcm_uframes_t offset, snd_pcm_uframes_t avail)
+{
+ /* FIXME: do a long path if this doesn't hold */
+ g_assert (dst[1].first - dst[0].first == 16);
+ g_assert (dst[0].addr == dst[1].addr);
+ g_assert (dst[0].step == dst[1].step);
+ g_assert (dst[0].step == 32);
+
+ memset (dst[0].addr + offset * dst[0].step / 8, 0, avail * 4);
+ swfdec_audio_render (stream->audio, dst[0].addr + offset * dst[0].step / 8,
+ stream->offset, avail);
+ //g_print ("rendering %u %u\n", stream->offset, (guint) avail);
+ return avail;
+}
+
+static gboolean
+try_write (Stream *stream)
+{
+ snd_pcm_sframes_t avail_result;
+ snd_pcm_uframes_t offset, avail;
+ const snd_pcm_channel_area_t *dst;
+
+ while (TRUE) {
+ avail_result = snd_pcm_avail_update (stream->pcm);
+ ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE);
+ if (avail_result == 0)
+ return TRUE;
+ avail = avail_result;
+ ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail),
+ "snd_pcm_mmap_begin failed", FALSE);
+ //g_print (" avail = %u\n", (guint) avail);
+
+ avail = write_player (stream, dst, offset, avail);
+ if (snd_pcm_mmap_commit (stream->pcm, offset, avail) < 0) {
+ g_printerr ("snd_pcm_mmap_commit failed\n");
+ return FALSE;
+ }
+ stream->offset += avail;
+ //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail);
+ }
+ return TRUE;
+}
+
+static void
+swfdec_stream_remove_handlers (Stream *stream)
+{
+ unsigned int i;
+
+ for (i = 0; i < stream->n_sources; i++) {
+ if (stream->sources[i]) {
+ g_source_destroy (stream->sources[i]);
+ g_source_unref (stream->sources[i]);
+ stream->sources[i] = NULL;
+ }
+ }
+}
+
+static void swfdec_stream_start (Stream *stream);
+static gboolean
+handle_stream (GIOChannel *source, GIOCondition cond, gpointer data)
+{
+ Stream *stream = data;
+ snd_pcm_state_t state;
+
+ state = snd_pcm_state (stream->pcm);
+ if (state != SND_PCM_STATE_RUNNING) {
+ swfdec_stream_start (stream);
+ } else {
+ try_write (stream);
+ }
+ return TRUE;
+}
+
+static void
+swfdec_stream_install_handlers (Stream *stream)
+{
+ if (stream->n_sources > 0) {
+ struct pollfd polls[stream->n_sources];
+ unsigned int i, count;
+ if (stream->n_sources > 1)
+ g_printerr ("attention: more than one fd!\n");
+ count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources);
+ for (i = 0; i < count; i++) {
+ if (stream->sources[i] != NULL)
+ continue;
+ GIOChannel *channel = g_io_channel_unix_new (polls[i].fd);
+ stream->sources[i] = g_io_create_watch (channel, polls[i].events);
+ g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH);
+ g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL);
+ g_io_channel_unref (channel);
+ g_source_attach (stream->sources[i], stream->sound->context);
+ }
+ }
+}
+
+static void
+swfdec_stream_start (Stream *stream)
+{
+ snd_pcm_state_t state = snd_pcm_state (stream->pcm);
+ switch (state) {
+ case SND_PCM_STATE_XRUN:
+ ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",);
+ //g_print ("XRUN!\n");
+ /* fall through */
+ case SND_PCM_STATE_SUSPENDED:
+ case SND_PCM_STATE_PREPARED:
+ stream->offset = 0;
+ //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay);
+ if (try_write (stream)) {
+ ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",);
+ swfdec_stream_install_handlers (stream);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+swfdec_stream_open (Sound *sound, SwfdecAudio *audio)
+{
+ Stream *stream;
+ snd_pcm_t *ret;
+ snd_pcm_hw_params_t *hw_params;
+ unsigned int rate;
+ snd_pcm_uframes_t uframes;
+
+ /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */
+ ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK),
+ "Failed to open sound device", );
+
+ snd_pcm_hw_params_alloca (&hw_params);
+ if (snd_pcm_hw_params_any (ret, hw_params) < 0) {
+ g_printerr ("No sound format available\n");
+ return;
+ }
+ if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
+ g_printerr ("Failed setting access\n");
+ goto fail;
+ }
+ if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) {
+ g_printerr ("Failed setting format\n");
+ goto fail;
+ }
+ if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) {
+ g_printerr ("Failed setting channels\n");
+ goto fail;
+ }
+ rate = 44100;
+ if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) {
+ g_printerr ("Failed setting rate\n");
+ goto fail;
+ }
+ uframes = 16384;
+ if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) {
+ g_printerr ("Failed setting buffer size\n");
+ goto fail;
+ }
+ if (snd_pcm_hw_params (ret, hw_params) < 0) {
+ g_printerr ("Could not set hardware parameters\n");
+ goto fail;
+ }
+#if 0
+ {
+ snd_output_t *log;
+ snd_output_stdio_attach (&log, stderr, 0);
+ snd_pcm_hw_params_dump (hw_params, log);
+ }
+#endif
+ stream = g_new0 (Stream, 1);
+ stream->sound = sound;
+ stream->audio = g_object_ref (audio);
+ stream->pcm = ret;
+ stream->n_sources = snd_pcm_poll_descriptors_count (ret);
+ if (stream->n_sources > 0)
+ stream->sources = g_new0 (GSource *, stream->n_sources);
+ sound->streams = g_list_prepend (sound->streams, stream);
+ swfdec_stream_start (stream);
+ return;
+
+fail:
+ snd_pcm_close (ret);
+}
+
+static void
+swfdec_stream_close (Stream *stream)
+{
+ ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing");
+ swfdec_stream_remove_handlers (stream);
+ g_free (stream->sources);
+ stream->sound->streams = g_list_remove (stream->sound->streams, stream);
+ g_object_unref (stream->audio);
+ g_free (stream);
+}
+
+/*** SOUND ***/
+
+static void
+advance_before (SwfdecPlayer *player, guint msecs, guint audio_samples, gpointer data)
+{
+ Sound *sound = data;
+ GList *walk;
+
+ for (walk = sound->streams; walk; walk = walk->next) {
+ Stream *stream = walk->data;
+ if (audio_samples >= stream->offset) {
+ stream->offset = 0;
+ } else {
+ stream->offset -= audio_samples;
+ }
+ }
+}
+
+static void
+audio_added (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound)
+{
+ swfdec_stream_open (sound, audio);
+}
+
+static void
+audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound)
+{
+ GList *walk;
+
+ for (walk = sound->streams; walk; walk = walk->next) {
+ Stream *stream = walk->data;
+ if (stream->audio == audio) {
+ swfdec_stream_close (stream);
+ return;
+ }
+ }
+ g_assert_not_reached ();
+}
+
+gpointer
+swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
+{
+ Sound *sound;
+ const GList *walk;
+
+ g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+ g_return_val_if_fail (context != NULL, NULL);
+
+ sound = g_new0 (Sound, 1);
+ sound->player = g_object_ref (player);
+ g_signal_connect (player, "advance", G_CALLBACK (advance_before), sound);
+ g_signal_connect (player, "audio-added", G_CALLBACK (audio_added), sound);
+ g_signal_connect (player, "audio-removed", G_CALLBACK (audio_removed), sound);
+ for (walk = swfdec_player_get_audio (player); walk; walk = walk->next) {
+ swfdec_stream_open (sound, walk->data);
+ }
+ g_main_context_ref (context);
+ sound->context = context;
+ return sound;
+}
+
+void
+swfdec_playback_close (gpointer data)
+{
+ Sound *sound = data;
+#define REMOVE_HANDLER_FULL(obj,func,data,count) G_STMT_START {\
+ if (g_signal_handlers_disconnect_by_func ((obj), \
+ G_CALLBACK (func), (data)) != (count)) { \
+ g_assert_not_reached (); \
+ } \
+} G_STMT_END
+#define REMOVE_HANDLER(obj,func,data) REMOVE_HANDLER_FULL (obj, func, data, 1)
+
+ while (sound->streams)
+ swfdec_stream_close (sound->streams->data);
+ REMOVE_HANDLER (sound->player, advance_before, sound);
+ REMOVE_HANDLER (sound->player, audio_added, sound);
+ REMOVE_HANDLER (sound->player, audio_removed, sound);
+ g_object_unref (sound->player);
+ g_main_context_unref (sound->context);
+ g_free (sound);
+}
+
+
diff --git a/player/swfdec_playback_none.c b/player/swfdec_playback_none.c
new file mode 100644
index 0000000..6464a4a
--- /dev/null
+++ b/player/swfdec_playback_none.c
@@ -0,0 +1,38 @@
+/* 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_playback.h"
+
+/* STUBS ONLY - audio is disabled */
+
+gpointer
+swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
+{
+ return GINT_TO_POINTER (-1);
+}
+
+void
+swfdec_playback_close (gpointer sound)
+{
+ g_assert (sound == GINT_TO_POINTER (-1));
+}
diff-tree f9f53b7a60b641e2ba5c846430f2fb48ac013eb0 (from 2cb8680a8577ff5d018b50e7da55c233e8eaa4af)
Author: Benjamin Otte <otte at gnome.org>
Date: Mon Jan 29 22:31:13 2007 +0100
enable gtk-doc in autogen.sh
developers are supposed to ensure that docs build and make dist requires it
diff --git a/autogen.sh b/autogen.sh
index 13824b4..fee343b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,3 +1,3 @@
#!/bin/sh
autoreconf -i -f &&
-./configure --enable-maintainer-mode --disable-static $@
+./configure --enable-maintainer-mode --disable-static --enable-gtk-doc $@
diff-tree 4e7806e7020535920cbb2009ed8b039fd64c046c (from 2cb8680a8577ff5d018b50e7da55c233e8eaa4af)
Author: Laszlo (Laca) Peter <laca at sun.com>
Date: Fri Jan 26 14:57:50 2007 -0800
Bug #9660: Fix build on Solaris.
diff --git a/libswfdec/swfdec_debug.h b/libswfdec/swfdec_debug.h
index 66e116a..2a59774 100644
--- a/libswfdec/swfdec_debug.h
+++ b/libswfdec/swfdec_debug.h
@@ -46,7 +46,7 @@ enum {
#define SWFDEC_DEBUG_LEVEL(level,...) (void) 0
#else
#define SWFDEC_DEBUG_LEVEL(level,...) \
- swfdec_debug_log ((level), __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
+ swfdec_debug_log ((level), __FILE__, G_GNUC_FUNCTION, __LINE__, __VA_ARGS__)
#endif
void swfdec_debug_log (unsigned int level, const char *file, const char *function,
More information about the Swfdec
mailing list