📄 swfdec_as_context.c
字号:
g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context)); if (context->state == SWFDEC_AS_CONTEXT_ABORTED) return; g_return_if_fail (context->frame == NULL); if (swfdec_as_context_needs_gc (context)) swfdec_as_context_gc (context);}/*** SWFDEC_AS_CONTEXT ***/enum { TRACE, LAST_SIGNAL};enum { PROP_0, PROP_DEBUGGER, PROP_UNTIL_GC};G_DEFINE_TYPE (SwfdecAsContext, swfdec_as_context, G_TYPE_OBJECT)static guint signals[LAST_SIGNAL] = { 0, };static voidswfdec_as_context_get_property (GObject *object, guint param_id, GValue *value, GParamSpec * pspec){ SwfdecAsContext *context = SWFDEC_AS_CONTEXT (object); switch (param_id) { case PROP_DEBUGGER: g_value_set_object (value, context->debugger); break; case PROP_UNTIL_GC: g_value_set_ulong (value, (gulong) context->memory_until_gc); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; }}static voidswfdec_as_context_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec * pspec){ SwfdecAsContext *context = SWFDEC_AS_CONTEXT (object); switch (param_id) { case PROP_DEBUGGER: context->debugger = SWFDEC_AS_DEBUGGER (g_value_dup_object (value)); break; case PROP_UNTIL_GC: context->memory_until_gc = g_value_get_ulong (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; }}static voidswfdec_as_context_dispose (GObject *object){ SwfdecAsContext *context = SWFDEC_AS_CONTEXT (object); while (context->stack) swfdec_as_stack_pop_segment (context); swfdec_as_context_collect (context); if (context->memory != 0) { g_critical ("%zu bytes of memory left over\n", context->memory); } g_assert (g_hash_table_size (context->objects) == 0); g_hash_table_destroy (context->objects); g_hash_table_destroy (context->strings); g_rand_free (context->rand); if (context->debugger) { g_object_unref (context->debugger); context->debugger = NULL; } G_OBJECT_CLASS (swfdec_as_context_parent_class)->dispose (object);}static voidswfdec_as_context_class_init (SwfdecAsContextClass *klass){ GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = swfdec_as_context_dispose; object_class->get_property = swfdec_as_context_get_property; object_class->set_property = swfdec_as_context_set_property; g_object_class_install_property (object_class, PROP_DEBUGGER, g_param_spec_object ("debugger", "debugger", "debugger used in this player", SWFDEC_TYPE_AS_DEBUGGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_UNTIL_GC, g_param_spec_ulong ("memory-until-gc", "memory until gc", "amount of bytes that need to be allocated before garbage collection triggers", 0, G_MAXULONG, 8 * 1024 * 1024, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); /** * SwfdecAsContext::trace: * @context: the #SwfdecAsContext affected * @text: the debugging string * * Emits a debugging string while running. The effect of calling any swfdec * functions on the emitting @context is undefined. */ signals[TRACE] = g_signal_new ("trace", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); klass->mark = swfdec_as_context_do_mark;}static voidswfdec_as_context_init (SwfdecAsContext *context){ const char *s; context->strings = g_hash_table_new (g_str_hash, g_str_equal); context->objects = g_hash_table_new (g_direct_hash, g_direct_equal); for (s = swfdec_as_strings; *s == '\2'; s += strlen (s) + 1) { g_hash_table_insert (context->strings, (char *) s + 1, (char *) s); } g_assert (*s == 0); context->global = swfdec_as_object_new_empty (context); context->rand = g_rand_new (); g_get_current_time (&context->start_time);}/*** STRINGS ***/static const char *swfdec_as_context_create_string (SwfdecAsContext *context, const char *string, gsize len){ char *new; if (!swfdec_as_context_use_mem (context, sizeof (char) * (2 + len))) return SWFDEC_AS_STR_EMPTY; new = g_slice_alloc (2 + len); memcpy (&new[1], string, len); new[len + 1] = 0; new[0] = 0; /* GC flags */ g_hash_table_insert (context->strings, new + 1, new); return new + 1;}/** * swfdec_as_context_get_string: * @context: a #SwfdecAsContext * @string: a sting that is not garbage-collected * * Gets the garbage-collected version of @string. You need to call this function * for every not garbage-collected string that you want to use in Swfdecs script * interpreter. * * Returns: the garbage-collected version of @string **/const char *swfdec_as_context_get_string (SwfdecAsContext *context, const char *string){ const char *ret; gsize len; g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL); g_return_val_if_fail (string != NULL, NULL); if (g_hash_table_lookup_extended (context->strings, string, (gpointer) &ret, NULL)) return ret; len = strlen (string); return swfdec_as_context_create_string (context, string, len);}/** * swfdec_as_context_give_string: * @context: a #SwfdecAsContext * @string: string to make refcounted * * Takes ownership of @string and returns a refcounted version of the same * string. This function is the same as swfdec_as_context_get_string(), but * takes ownership of @string. * * Returns: A refcounted string **/const char *swfdec_as_context_give_string (SwfdecAsContext *context, char *string){ const char *ret; g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL); g_return_val_if_fail (string != NULL, NULL); ret = swfdec_as_context_get_string (context, string); g_free (string); return ret;}/** * swfdec_as_context_is_constructing: * @context: a #SwfdecAsConstruct * * Determines if the contexxt is currently constructing. This information is * used by various constructors to do different things when they are * constructing and when they are not. The Boolean, Number and String functions * for example setup the newly constructed objects when constructing but only * cast the provided argument when being called. * * Returns: %TRUE if the currently executing frame is a constructor **/gbooleanswfdec_as_context_is_constructing (SwfdecAsContext *context){ g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), FALSE); return context->frame && context->frame->construct;}/** * swfdec_as_context_get_frame: * @context: a #SwfdecAsContext * * This is a debugging function. It gets the topmost stack frame that is * currently executing. If no function is executing, %NULL is returned. You can * easily get a backtrace with code like this: * |[for (frame = swfdec_as_context_get_frame (context); frame != NULL; * frame = swfdec_as_frame_get_next (frame)) { * char *s = swfdec_as_object_get_debug (SWFDEC_AS_OBJECT (frame)); * g_print ("%s\n", s); * g_free (s); * }]| * * Returns: the currently executing frame or %NULL if none **/SwfdecAsFrame *swfdec_as_context_get_frame (SwfdecAsContext *context){ g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL); return context->frame;}/** * swfdec_as_context_get_time: * @context: a #SwfdecAsContext * @tv: a #GTimeVal to be set to the context's time * * This function queries the time to be used inside this context. By default, * this is the same as g_get_current_time(), but it may be overwriten to allow * things such as slower or faster playback. **/voidswfdec_as_context_get_time (SwfdecAsContext *context, GTimeVal *tv){ SwfdecAsContextClass *klass; g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context)); g_return_if_fail (tv != NULL); klass = SWFDEC_AS_CONTEXT_GET_CLASS (context); if (klass->get_time) klass->get_time (context, tv); else g_get_current_time (tv);}/** * swfdec_as_context_run: * @context: a #SwfdecAsContext * * Continues running the script engine. Executing code in this engine works * in 2 steps: First, you push the frame to be executed onto the stack, then * you call this function to execute it. So this function is the single entry * point to script execution. This might be helpful when debugging your * application. * <note>A lot of convenience functions like swfdec_as_object_run() call this * function automatically.</note> **/voidswfdec_as_context_run (SwfdecAsContext *context){ SwfdecAsFrame *frame, *last_frame; SwfdecScript *script; const SwfdecActionSpec *spec; SwfdecActionExec exec; guint8 *startpc, *pc, *endpc, *nextpc;#ifndef G_DISABLE_ASSERT SwfdecAsValue *check;#endif guint action, len; guint8 *data; int version; void (* step) (SwfdecAsDebugger *debugger, SwfdecAsContext *context); gboolean check_scope; /* some opcodes avoid a scope check */ g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context)); if (context->frame == NULL || context->state == SWFDEC_AS_CONTEXT_ABORTED) return; if (context->debugger) { SwfdecAsDebuggerClass *klass = SWFDEC_AS_DEBUGGER_GET_CLASS (context->debugger); step = klass->step; } else { step = NULL; } last_frame = context->last_frame; context->last_frame = context->frame->next;start: /* setup data */ frame = context->frame; if (frame == context->last_frame) goto out; if (context->call_depth > 256) { /* we've exceeded our maximum call depth, throw an error and abort */ swfdec_as_context_abort (context, "Stack overflow"); return; } if (SWFDEC_IS_AS_NATIVE_FUNCTION (frame->function)) { SwfdecAsNativeFunction *native = SWFDEC_AS_NATIVE_FUNCTION (frame->function); SwfdecAsValue rval = { 0, }; if (frame->argc >= native->min_args && (native->type == 0 || g_type_is_a (G_OBJECT_TYPE (frame->thisp), native->type))) { SwfdecAsValue *argv; /* accumulate argv */ if (frame->argc == 0 || frame->argv != NULL) { /* FIXME FIXME FIXME: no casting here please! */ argv = (SwfdecAsValue *) frame->argv; } else { SwfdecAsStack *stack; SwfdecAsValue *cur; guint i, n; if (frame->argc > 128) { SWFDEC_FIXME ("allow calling native functions with more than 128 args"); n = 128; } else { n = frame->argc; } argv = g_new (SwfdecAsValue, n); stack = context->stack; cur = context->cur; for (i = 0; i < n; i++) { if (cur <= &stack->elements[0]) { stack = stack->next; cur = &stack->elements[stack->used_elements]; } cur--; argv[i] = *cur; } } native->native (context, frame->thisp, frame->argc, argv, &rval); if (argv != frame->argv) g_free (argv); } swfdec_as_frame_return (frame, &rval); goto start; } g_assert (frame->script); g_assert (frame->target); script = frame->script; version = SWFDEC_AS_EXTRACT_SCRIPT_VERSION (script->version); context->version = script->version; startpc = script->buffer->data; endpc = startpc + script->buffer->length; pc = frame->pc; check_scope = TRUE; while (context->state < SWFDEC_AS_CONTEXT_ABORTED) { if (pc == endpc) { swfdec_as_frame_return (frame, NULL); goto start; } if (pc < startpc || pc >= endpc) { SWFDEC_ERROR ("pc %p not in valid range [%p, %p) anymore", pc, startpc, endpc); goto error; } if (check_scope) swfdec_as_frame_check_scope (frame); /* decode next action */ action = *pc; if (action == 0) { swfdec_as_frame_return (frame, NULL); goto start; } /* invoke debugger if there is one */ if (step) { frame->pc = pc; (* step) (context->debugger, context); if (frame != context->frame || frame->pc != pc) { goto start; } } /* prepare action */ spec = swfdec_as_actions + action; if (action & 0x80) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -