4 #include "swfdec_internal.h"
8 constant_pool_ref (ConstantPool
*pool
)
14 constant_pool_unref (ConstantPool
*pool
)
16 if (--pool
->refcount
== 0) {
19 for (i
=0;i
<pool
->n_constants
;i
++){
20 g_free(pool
->constants
[i
]);
22 g_free (pool
->constants
);
28 pc_is_valid (SwfdecActionContext
*context
, unsigned char *pc
)
30 unsigned char *startpc
;
33 startpc
= context
->bits
.buffer
->data
;
34 endpc
= context
->bits
.buffer
->data
+ context
->bits
.buffer
->length
;
35 /* Use a <= here because sometimes you'll get a jump to endpc in functions as
36 * a way of branching to return (without an ActionReturn). action_script_call
37 * will handle making the return happen.
39 if (pc
>= startpc
&& pc
<= endpc
) {
46 void swfdec_init_context (SwfdecDecoder
* s
)
48 SwfdecActionContext
*context
;
52 context
= g_malloc0 (sizeof(SwfdecActionContext
));
55 context
->call_stack
= g_queue_new();
57 context
->jsrt
= JS_NewRuntime (64L * 1024L * 1024L);
61 context
->jscx
= JS_NewContext (context
->jsrt
, 8192);
63 JS_SetContextPrivate (context
->jscx
, context
);
65 swfdec_init_context_builtins (context
);
67 context
->stack
= JS_NewArrayObject (context
->jscx
, 0, NULL
);
68 JS_AddRoot (context
->jscx
, &context
->stack
);
69 context
->stack_top
= 0;
71 context
->registers
= JS_NewArrayObject (context
->jscx
, 0, NULL
);
72 JS_AddRoot (context
->jscx
, &context
->registers
);
73 for (i
= 0; i
< 4; i
++) {
75 JS_SetElement (context
->jscx
, context
->registers
, i
, &val
);
78 #if SWFDEC_ACTIONS_DEBUG_GC
84 action_script_call(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
89 ActionFuncEntry
*func_entry
;
91 SwfdecActionContext
*context
;
95 /* argv[-2] is funobj, argc[-1] is this, argv[0] through argv[argc-1] are the
96 * args, and beyond that are 3 tag temporaries and then the array object for
100 context
= JS_GetContextPrivate (cx
);
101 jsfunc
= JS_ValueToFunction (cx
, argv
[-2]);
104 /* FIXME: set limits on recursion to prevent stack exhaustion */
106 /* Native methods short circuit this whole mess. */
108 return func
->meth (context
, argc
);
111 frame
= g_malloc0 (sizeof(CallFrame
));
112 frame
->returnpc
= context
->pc
;
113 frame
->is_function2
= func
->is_function2
;
114 frame
->bits
.buffer
= func
->buffer
;
115 frame
->bits
.ptr
= func
->pc
;
117 frame
->bits
.end
= func
->pc
+ func
->code_size
;
118 frame
->returnbuffer
= context
->bits
.buffer
;
119 frame
->returnpool
= context
->constantpool
;
120 frame
->returnargv
= context
->tag_argv
;
121 frame
->returnargc
= context
->tag_argc
;
122 context
->constantpool
= func
->constantpool
;
123 if (func
->constantpool
)
124 constant_pool_ref(func
->constantpool
);
125 context
->pc
= func
->pc
;
126 context
->tag_argv
= argv
;
127 context
->tag_argc
= argc
;
128 g_queue_push_head (context
->call_stack
, frame
);
129 context
->call_depth
++;
131 if (func
->is_function2
) {
135 frame
->registers
= JS_NewArrayObject (context
->jscx
, 0, NULL
);
136 argv
[argc
+ 3] = OBJECT_TO_JSVAL(frame
->registers
);
139 if (func
->preload_this
) {
140 jsval val
= OBJECT_TO_JSVAL(obj
);
141 JS_SetElement (context
->jscx
, frame
->registers
, reg
++, &val
);
143 /* FIXME: load arguments */
144 if (func
->preload_super
) {
145 jsval val
= OBJECT_TO_JSVAL(JS_GetConstructor (context
->jscx
,
146 JS_GetParent (context
->jscx
, obj
)));
147 JS_SetElement (context
->jscx
, frame
->registers
, reg
++, &val
);
149 if (func
->preload_root
) {
150 jsval val
= OBJECT_TO_JSVAL(context
->root
);
151 JS_SetElement (context
->jscx
, frame
->registers
, reg
++, &val
);
153 if (func
->preload_parent
) {
154 jsval val
= OBJECT_TO_JSVAL(JS_GetParent (context
->jscx
, obj
));
155 JS_SetElement (context
->jscx
, frame
->registers
, reg
++, &val
);
157 if (func
->preload_global
) {
158 jsval val
= OBJECT_TO_JSVAL(context
->global
);
159 JS_SetElement (context
->jscx
, frame
->registers
, reg
++, &val
);
162 for (i
= 0; (i
< argc
) && (i
< func
->num_params
); i
++) {
163 if (func
->param_regs
[i
]) {
164 JS_SetElement (context
->jscx
, frame
->registers
, func
->param_regs
[i
],
167 SWFDEC_WARNING ("named arguments unsupported");
172 context
->bits
.buffer
= frame
->bits
.buffer
; /* for pc_is_valid () */
174 while (context
->pc
< frame
->bits
.end
) {
175 #if SWFDEC_ACTIONS_DEBUG_GC
176 JS_GC(context
->jscx
);
179 action
= swfdec_bits_get_u8 (&frame
->bits
);
181 len
= swfdec_bits_get_u16 (&frame
->bits
);
182 context
->bits
.buffer
= frame
->bits
.buffer
;
183 context
->bits
.ptr
= frame
->bits
.ptr
;
184 context
->bits
.idx
= 0;
185 context
->bits
.end
= frame
->bits
.ptr
+ len
;
189 frame
->bits
.ptr
+= len
;
190 context
->pc
= frame
->bits
.ptr
;
191 context
->action
= action
;
193 func_entry
= get_action (action
);
195 if (context
->skip
> 0) {
196 SWFDEC_DEBUG ("[skip] depth %d, action 0x%02x (%s)", context
->call_depth
,
197 action
, func_entry
? func_entry
->name
: "(unknown)");
202 SWFDEC_DEBUG ("depth %d, action 0x%02x (%s)", context
->call_depth
,
203 action
, func_entry
? func_entry
->name
: "(unknown)");
205 func_entry
->func (context
);
207 SWFDEC_WARNING ("unknown action 0x%02x, ignoring", action
);
212 if (context
->bits
.ptr
< context
->bits
.end
) {
213 SWFDEC_ERROR ("action 0x%02x didn't read all data (%d < %d)",
215 context
->bits
.ptr
- (frame
->bits
.ptr
- len
),
216 context
->bits
.end
- (frame
->bits
.ptr
- len
));
218 if (context
->bits
.ptr
> context
->bits
.end
) {
219 SWFDEC_ERROR ("action 0x%02x read past end of buffer (%d > %d)",
221 context
->bits
.ptr
- (frame
->bits
.ptr
- len
),
222 context
->bits
.end
- (frame
->bits
.ptr
- len
));
229 frame
->bits
.ptr
= context
->pc
;
231 if (context
->error
) {
233 SWFDEC_ERROR ("action script error (see warnings)");
237 SWFDEC_DEBUG("returning from actionscript call");
239 *rval
= stack_pop (context
);
241 if (context
->constantpool
) {
242 constant_pool_unref (context
->constantpool
);
244 context
->constantpool
= frame
->returnpool
;
245 context
->bits
.buffer
= frame
->returnbuffer
;
246 context
->pc
= frame
->returnpc
;
247 context
->tag_argv
= frame
->returnargv
;
248 context
->tag_argc
= frame
->returnargc
;
249 g_queue_pop_head (context
->call_stack
);
250 context
->call_depth
--;
257 swfdec_action_script_execute (SwfdecDecoder
* s
, SwfdecBuffer
* buffer
)
259 SwfdecActionContext
*context
;
262 ScriptFunction
*func
;
264 if (!s
->parse_sprite
) {
265 s
->parse_sprite
= s
->main_sprite
;
266 s
->parse_sprite_seg
= s
->main_sprite_seg
;
269 SWFDEC_INFO ("swfdec_action_script_execute (sprite %d) %p %p %d",
270 SWFDEC_OBJECT(s
->parse_sprite
)->id
, buffer
, buffer
->data
, buffer
->length
);
272 if (s
->context
== NULL
)
273 swfdec_init_context (s
);
274 context
= s
->context
;
276 #if SWFDEC_ACTIONS_DEBUG_GC
277 JS_GC(context
->jscx
);
280 func
= g_malloc0 (sizeof (ScriptFunction
));
282 SWFDEC_ERROR ("out of memory");
286 func
->num_params
= 0;
287 func
->code_size
= buffer
->length
;
288 func
->pc
= buffer
->data
;
289 func
->buffer
= buffer
;
291 jsfunc
= JS_NewFunction (context
->jscx
, action_script_call
, func
->num_params
,
292 0, context
->global
, "");
295 JS_CallFunction (context
->jscx
, context
->root
, jsfunc
, 0, NULL
, &rval
);
297 /* FIXME: Deallocate the function? */
299 /* FIXME: as of Flash 6/7, stack gets emptied at the end of every action
300 * block. -- flasm.sf.net
308 stack_pop (SwfdecActionContext
*context
)
313 if (context
->stack_top
== 0)
316 ok
= JS_GetElement (context
->jscx
, context
->stack
, --context
->stack_top
,
320 SWFDEC_WARNING("Couldn't pop element");
328 stack_push (SwfdecActionContext
*context
, jsval val
)
332 #if SWFDEC_ACTIONS_DEBUG_GC
333 JS_GC(context
->jscx
);
336 ok
= JS_SetElement (context
->jscx
, context
->stack
, context
->stack_top
++,
340 SWFDEC_WARNING("Couldn't push element");
344 name_object (SwfdecActionContext
*context
, JSObject
*obj
)
346 /* FIXME: I envision this function walking the tree from _global, trying to
347 * find a name for the object that's on the stack. That might be
348 * unreasonable. For now, identify if the object is _global.
351 if (obj
== context
->global
) {
352 return g_strdup ("_global");
353 } else if (obj
== context
->root
) {
354 return g_strdup ("_root");
356 char *name
= g_malloc (20);
357 g_snprintf(name
, 20, "%p", obj
);
363 stack_show (SwfdecActionContext
*context
)
368 SWFDEC_INFO ("Stack:");
369 for (i
= context
->stack_top
- 1; i
>= 0; i
--) {
370 JS_GetElement (context
->jscx
, context
->stack
, i
, &val
);
371 if (JSVAL_IS_NULL(val
)) {
372 SWFDEC_INFO (" %d: (null)", i
);
373 } else if (JSVAL_IS_VOID(val
)) {
374 SWFDEC_INFO (" %d: (undefined)", i
);
375 } else if (JSVAL_IS_STRING(val
)) {
376 SWFDEC_INFO (" %d: \"%s\"", i
, JS_GetStringBytes(JSVAL_TO_STRING (val
)));
377 } else if (JSVAL_IS_INT(val
)) {
378 SWFDEC_INFO (" %d: %d", i
, JSVAL_TO_INT (val
));
379 } else if (JSVAL_IS_DOUBLE(val
)) {
380 SWFDEC_INFO (" %d: %g", i
, *JSVAL_TO_DOUBLE (val
));
381 } else if (JSVAL_IS_BOOLEAN(val
)) {
382 SWFDEC_INFO (" %d: %s", i
, JSVAL_TO_BOOLEAN (val
) ? "true" : "false");
383 } else if (JSVAL_IS_OBJECT(val
)) {
384 char *name
= name_object (context
, JSVAL_TO_OBJECT(val
));
385 SWFDEC_INFO (" %d: obj (%s)", i
, name
);
388 SWFDEC_INFO (" %d: unknown type", i
);
394 stack_show_value (SwfdecActionContext
*context
, jsval val
)
398 if (JSVAL_IS_NULL(val
)) {
399 SWFDEC_INFO (" %d: (null)", i
);
400 } else if (JSVAL_IS_VOID(val
)) {
401 SWFDEC_INFO (" %d: (undefined)", i
);
402 } else if (JSVAL_IS_STRING(val
)) {
403 SWFDEC_INFO (" %d: \"%s\"", i
, JS_GetStringBytes(JSVAL_TO_STRING (val
)));
404 } else if (JSVAL_IS_INT(val
)) {
405 SWFDEC_INFO (" %d: %d", i
, JSVAL_TO_INT (val
));
406 } else if (JSVAL_IS_DOUBLE(val
)) {
407 SWFDEC_INFO (" %d: %g", i
, *JSVAL_TO_DOUBLE (val
));
408 } else if (JSVAL_IS_BOOLEAN(val
)) {
409 SWFDEC_INFO (" %d: %s", i
, JSVAL_TO_BOOLEAN (val
) ? "true" : "false");
410 } else if (JSVAL_IS_OBJECT(val
)) {
411 char *name
= name_object (context
, JSVAL_TO_OBJECT(val
));
412 SWFDEC_INFO (" %d: obj (%s)", i
, name
);
415 SWFDEC_INFO (" %d: unknown type", i
);
419 /* Given a jsval, convert it into an object. JS_ValueToObject appears to have
420 * some side effect when working on an existing object, at least. While I'm
421 * here, make it print out when we actually convert a non-object to object.
422 * Perhaps this never occurs in actionscript bytecode.
425 jsval_as_object (SwfdecActionContext
*context
, jsval val
)
427 if (JSVAL_IS_OBJECT(val
)) {
428 return JSVAL_TO_OBJECT(val
);
430 JSObject
*obj
= NULL
;
433 SWFDEC_INFO("Converting value 0x%x to object", val
);
434 ok
= JS_ValueToObject (context
->jscx
, val
, &obj
);
436 SWFDEC_ERROR("Couldn't convert value %x to object", val
);