📄 swfdec_script.c
字号:
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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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_get_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) { fun->nvars = swfdec_bits_get_u8 (&bits) + 1; flags = swfdec_bits_get_u16 (&bits); preloads = g_new0 (guint8, n_args); } else { fun->nvars = 5; } 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 >= fun->nvars) { SWFDEC_ERROR ("argument %u is preloaded into register %u out of %u", i, preload, fun->nvars); 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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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 JSBoolswfdec_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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -