⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 swfdec_script.c

📁 Swfdec still is development software, but has also followed a rigid no-crashes-allowed policy. I b
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Swfdec * Copyright (C) 2007 Benjamin Otte <otte@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_script.h"#include "swfdec_debug.h"#include "swfdec_debugger.h"#include "swfdec_scriptable.h"#include "js/jscntxt.h"#include "js/jsinterp.h"#include <errno.h>#include <math.h>#include <string.h>#include "swfdec_decoder.h"#include "swfdec_js.h"#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"/* 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/*** CONSTANT POOLS ***/SwfdecConstantPool *swfdec_constant_pool_new_from_action (const guint8 *data, guint len){  guint8 *next;  guint i, n;  GPtrArray *pool;  if (len < 2) {    SWFDEC_ERROR ("constant pool too small");    return NULL;  }  n = GUINT16_FROM_LE (*((guint16*) data));  data += 2;  len -= 2;  pool = g_ptr_array_sized_new (n);  g_ptr_array_set_size (pool, n);  for (i = 0; i < n; i++) {    next = memchr (data, 0, len);    if (next == NULL) {      SWFDEC_ERROR ("not enough strings available");      g_ptr_array_free (pool, TRUE);      return NULL;    }    next++;    g_ptr_array_index (pool, i) = (gpointer) data;    len -= next - data;    data = next;  }  if (len != 0) {    SWFDEC_WARNING ("constant pool didn't consume whole buffer (%u bytes leftover)", len);  }  return pool;}guintswfdec_constant_pool_size (SwfdecConstantPool *pool){  return pool->len;}const char *swfdec_constant_pool_get (SwfdecConstantPool *pool, guint i){  g_assert (i < pool->len);  return g_ptr_array_index (pool, i);}voidswfdec_constant_pool_free (SwfdecConstantPool *pool){  g_ptr_array_free (pool, TRUE);}/* FIXME: this is a bit hacky */static SwfdecBuffer *swfdec_constant_pool_get_area (SwfdecScript *script, SwfdecConstantPool *pool){  guint8 *start;  SwfdecBuffer *buffer;  guint len;  if (pool->len == 0)    return NULL;  start = (guint8 *) g_ptr_array_index (pool, 0) - 5;  buffer = script->buffer;  if (start < buffer->data) {    /* DefineFunction inside DefineFunction */    g_assert (buffer->parent != NULL);    buffer = buffer->parent;    g_assert (start >= buffer->data);  }  g_assert (start + 3 < buffer->data + buffer->length);  g_assert (*start == 0x88);  len = 3 + (start[1] | start[2] << 8);  g_assert (start + len < buffer->data + buffer->length);  return swfdec_buffer_new_subbuffer (buffer, start - buffer->data, len);}/*** SUPPORT FUNCTIONS ***/static voidswfdec_script_add_to_player (SwfdecScript *script, SwfdecPlayer *player){  if (SWFDEC_IS_DEBUGGER (player)) {    swfdec_debugger_add_script (SWFDEC_DEBUGGER (player), script);    script->debugger = player;  }}/** * swfdec_script_ensure_stack: * @cx: #JSContext to check * @n_elements: number of elements the stack should contain * * Ensures that the stack is at least @n_elements values. If not enough stack * space is available, the stack is filled up with JSVAL_VOID. * * Returns: JS_TRUE on success or JS_FALSE on OOM **/static inline JSBoolswfdec_script_ensure_stack (JSContext *cx, guint n_elements){  JSStackFrame *fp = cx->fp;  guint current = (guint) (fp->sp - fp->spbase);  if (current >= n_elements)    return JS_TRUE;  if (n_elements > (guint) (fp->spend - fp->spbase)) {    SWFDEC_ERROR ("FIXME: implement stack expansion, we got an overflow (want %u, have %td)",	n_elements, (fp->spend - fp->spbase));    return JS_FALSE;  }  if (current) {    n_elements -= current;    memmove (fp->spbase + n_elements, fp->spbase, (fp->sp - fp->spbase) * sizeof (jsval));  }  fp->sp += n_elements;  while (n_elements)  {    n_elements--;    fp->spbase[n_elements] = JSVAL_VOID;  }  return JS_TRUE;}static gbooleanswfdec_action_has_register (JSContext *cx, guint i){  if (cx->fp->fun == NULL)    return i < 4;  else    return i < cx->fp->fun->nvars;}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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 doubleswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 intswfdec_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 JSBoolswfdec_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 voidswfdec_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 JSBoolswfdec_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];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -