2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301 USA
23 #include "swfdec_as_interpret.h"
24 #include "swfdec_as_array.h"
25 #include "swfdec_as_context.h"
26 #include "swfdec_as_frame_internal.h"
27 #include "swfdec_as_function.h"
28 #include "swfdec_as_script_function.h"
29 #include "swfdec_as_stack.h"
30 #include "swfdec_as_string.h"
31 #include "swfdec_as_strings.h"
32 #include "swfdec_as_super.h"
33 #include "swfdec_debug.h"
38 #include "swfdec_decoder.h"
39 #include "swfdec_movie.h"
40 #include "swfdec_player_internal.h"
41 #include "swfdec_sprite.h"
42 #include "swfdec_sprite_movie.h"
43 #include "swfdec_swf_instance.h"
45 /* Define this to get SWFDEC_WARN'd about missing properties of objects.
46 * This can be useful to find out about unimplemented native properties,
47 * but usually just causes a lot of spam. */
48 //#define SWFDEC_WARN_MISSING_PROPERTIES
50 /*** SUPPORT FUNCTIONS ***/
52 #define swfdec_action_has_register(cx, i) \
53 ((i) < (cx)->frame->n_registers)
55 /*** ALL THE ACTION IS HERE ***/
58 swfdec_action_stop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
60 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
61 SWFDEC_SPRITE_MOVIE (cx
->frame
->target
)->playing
= FALSE
;
63 SWFDEC_ERROR ("no movie to stop");
67 swfdec_action_play (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
69 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
70 SWFDEC_SPRITE_MOVIE (cx
->frame
->target
)->playing
= TRUE
;
72 SWFDEC_ERROR ("no movie to play");
76 swfdec_action_next_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
78 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
79 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
80 if (movie
->frame
< movie
->n_frames
) {
81 swfdec_sprite_movie_goto (movie
, movie
->frame
+ 1);
83 SWFDEC_INFO ("can't execute nextFrame, already at last frame");
86 SWFDEC_ERROR ("no movie to nextFrame on");
91 swfdec_action_previous_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
93 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
94 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
95 if (movie
->frame
> 1) {
96 swfdec_sprite_movie_goto (movie
, movie
->frame
- 1);
98 SWFDEC_INFO ("can't execute previousFrame, already at first frame");
101 SWFDEC_ERROR ("no movie to previousFrame on");
106 swfdec_action_goto_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
111 SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len
);
114 frame
= GUINT16_FROM_LE (*((guint16
*) data
));
115 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
116 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
117 swfdec_sprite_movie_goto (movie
, frame
+ 1);
118 movie
->playing
= FALSE
;
120 SWFDEC_ERROR ("no movie to goto on");
125 swfdec_action_goto_label (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
127 if (!memchr (data
, 0, len
)) {
128 SWFDEC_ERROR ("GotoLabel action does not specify a string");
132 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
133 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
135 if (movie
->sprite
== NULL
||
136 (frame
= swfdec_sprite_get_frame (movie
->sprite
, (const char *) data
)) == -1)
138 swfdec_sprite_movie_goto (movie
, frame
+ 1);
139 movie
->playing
= FALSE
;
141 SWFDEC_ERROR ("no movie to goto on");
145 /* returns: frame to go to or 0 on error */
147 swfdec_value_to_frame (SwfdecAsContext
*cx
, SwfdecSpriteMovie
*movie
, SwfdecAsValue
*val
)
151 if (movie
->sprite
== NULL
)
153 if (SWFDEC_AS_VALUE_IS_STRING (val
)) {
154 const char *name
= SWFDEC_AS_VALUE_GET_STRING (val
);
156 if (strchr (name
, ':')) {
157 SWFDEC_ERROR ("FIXME: handle targets");
159 /* treat valid encoded numbers as numbers, otherwise assume it's a frame label */
160 d
= swfdec_as_value_to_number (cx
, val
);
162 frame
= swfdec_sprite_get_frame (movie
->sprite
, name
) + 1;
165 } else if (SWFDEC_AS_VALUE_IS_NUMBER (val
)) {
166 frame
= swfdec_as_value_to_integer (cx
, val
);
168 SWFDEC_WARNING ("cannot convert value to frame number");
169 /* FIXME: how do we treat undefined etc? */
172 return frame
<= 0 ? 0 : frame
;
176 swfdec_action_goto_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
183 swfdec_bits_init_data (&bits
, data
, len
);
184 if (swfdec_bits_getbits (&bits
, 6)) {
185 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
187 bias
= swfdec_bits_getbit (&bits
);
188 play
= swfdec_bits_getbit (&bits
);
190 bias
= swfdec_bits_get_u16 (&bits
);
192 val
= swfdec_as_stack_peek (cx
, 1);
194 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
195 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
196 guint frame
= swfdec_value_to_frame (cx
, movie
, val
);
199 frame
= CLAMP (frame
, 1, movie
->n_frames
);
200 swfdec_sprite_movie_goto (movie
, frame
);
201 movie
->playing
= play
;
204 SWFDEC_ERROR ("no movie to GotoFrame2 on");
206 swfdec_as_stack_pop (cx
);
210 swfdec_script_skip_actions (SwfdecAsContext
*cx
, guint jump
)
212 SwfdecScript
*script
= cx
->frame
->script
;
213 guint8
*pc
= cx
->frame
->pc
;
214 guint8
*endpc
= script
->buffer
->data
+ script
->buffer
->length
;
216 /* jump instructions */
223 pc
+= 3 + GUINT16_FROM_LE (*((guint16
*) (pc
+ 1)));
227 } while (jump
-- > 0);
233 swfdec_action_wait_for_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
238 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
241 val
= cx
->fp
->sp
[-1];
243 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
244 SwfdecMovie
*movie
= SWFDEC_MOVIE (cx
->frame
->target
);
245 int frame
= swfdec_value_to_frame (cx
, movie
, val
);
246 guint jump
= data
[2];
250 if (SWFDEC_IS_ROOT_MOVIE (movie
)) {
251 SwfdecDecoder
*dec
= SWFDEC_ROOT_MOVIE (movie
)->decoder
;
252 loaded
= dec
->frames_loaded
;
253 g_assert (loaded
<= movie
->n_frames
);
255 loaded
= movie
->n_frames
;
257 if (loaded
<= (guint
) frame
)
258 swfdec_script_skip_actions (cx
, jump
);
260 SWFDEC_ERROR ("no movie to WaitForFrame2 on");
267 swfdec_action_wait_for_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
269 SwfdecSpriteMovie
*movie
;
270 guint frame
, jump
, loaded
;
273 SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len
);
276 if (!SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
277 SWFDEC_ERROR ("no movie for WaitForFrame");
281 movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
282 frame
= data
[0] || (data
[1] << 8);
284 if (SWFDEC_MOVIE (movie
)->swf
->movie
== movie
) {
285 SwfdecDecoder
*dec
= SWFDEC_MOVIE (movie
)->swf
->decoder
;
286 loaded
= dec
->frames_loaded
;
287 g_assert (loaded
<= movie
->n_frames
);
288 if (loaded
== dec
->frames_total
)
294 swfdec_script_skip_actions (cx
, jump
);
298 swfdec_action_constant_pool (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
300 SwfdecConstantPool
*pool
;
301 SwfdecAsFrame
*frame
;
304 pool
= swfdec_constant_pool_new_from_action (data
, len
, cx
->version
);
307 swfdec_constant_pool_attach_to_context (pool
, cx
);
308 if (frame
->constant_pool
)
309 swfdec_constant_pool_free (frame
->constant_pool
);
310 frame
->constant_pool
= pool
;
311 if (frame
->constant_pool_buffer
)
312 swfdec_buffer_unref (frame
->constant_pool_buffer
);
313 frame
->constant_pool_buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
314 data
- frame
->script
->buffer
->data
, len
);
318 swfdec_action_push (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
322 swfdec_bits_init_data (&bits
, data
, len
);
323 while (swfdec_bits_left (&bits
)) {
324 guint type
= swfdec_bits_get_u8 (&bits
);
325 SWFDEC_LOG ("push type %u", type
);
326 swfdec_as_stack_ensure_free (cx
, 1);
330 char *s
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
333 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
334 swfdec_as_context_give_string (cx
, s
));
338 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_push (cx
),
339 swfdec_bits_get_float (&bits
));
342 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
344 case 3: /* undefined */
345 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
347 case 4: /* register */
349 guint regnum
= swfdec_bits_get_u8 (&bits
);
350 if (!swfdec_action_has_register (cx
, regnum
)) {
351 SWFDEC_ERROR ("cannot Push register %u: not enough registers", regnum
);
352 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
354 *swfdec_as_stack_push (cx
) = cx
->frame
->registers
[regnum
];
358 case 5: /* boolean */
359 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
360 swfdec_bits_get_u8 (&bits
) ? TRUE
: FALSE
);
363 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_push (cx
),
364 swfdec_bits_get_double (&bits
));
366 case 7: /* 32bit int */
367 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_push (cx
),
368 (int) swfdec_bits_get_u32 (&bits
));
370 case 8: /* 8bit ConstantPool address */
372 guint i
= swfdec_bits_get_u8 (&bits
);
373 SwfdecConstantPool
*pool
= cx
->frame
->constant_pool
;
375 SWFDEC_ERROR ("no constant pool to push from");
378 if (i
>= swfdec_constant_pool_size (pool
)) {
379 SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
380 i
, swfdec_constant_pool_size (pool
));
383 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
384 swfdec_constant_pool_get (pool
, i
));
387 case 9: /* 16bit ConstantPool address */
389 guint i
= swfdec_bits_get_u16 (&bits
);
390 SwfdecConstantPool
*pool
= cx
->frame
->constant_pool
;
392 SWFDEC_ERROR ("no constant pool to push from");
395 if (i
>= swfdec_constant_pool_size (pool
)) {
396 SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
397 i
, swfdec_constant_pool_size (pool
));
400 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
401 swfdec_constant_pool_get (pool
, i
));
405 SWFDEC_ERROR ("Push: type %u not implemented", type
);
411 static SwfdecAsObject
*
412 super_special_movie_lookup_magic (SwfdecAsObject
*o
, const char *name
)
416 if (SWFDEC_IS_MOVIE (o
)) {
417 SwfdecMovie
*ret
= swfdec_movie_get_by_name (SWFDEC_MOVIE (o
), name
);
419 return SWFDEC_AS_OBJECT (ret
);
421 if (!swfdec_as_object_get_variable (o
, name
, &val
))
423 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
425 return SWFDEC_AS_VALUE_GET_OBJECT (&val
);
428 static SwfdecAsObject
*
429 swfdec_action_get_movie_by_slash_path (SwfdecAsContext
*cx
, const char *path
)
433 o
= cx
->frame
->target
;
434 if (!SWFDEC_IS_MOVIE (o
))
437 o
= SWFDEC_AS_OBJECT (swfdec_movie_get_root (SWFDEC_MOVIE (o
)));
441 char *slash
= strchr (path
, '/');
446 name
= swfdec_as_context_give_string (cx
, g_strndup (path
, slash
- path
));
449 name
= swfdec_as_context_get_string (cx
, path
);
450 path
+= strlen (path
);
452 o
= super_special_movie_lookup_magic (o
, name
);
453 if (!SWFDEC_IS_MOVIE (o
))
459 static SwfdecAsObject
*
460 swfdec_action_lookup_object (SwfdecAsContext
*cx
, const char *path
, const char *end
)
462 SwfdecAsObject
*o
= cx
->frame
->target
;
463 gboolean dot_allowed
= TRUE
;
466 g_assert (*end
== '.' || *end
== ':');
470 if (path
[0] == '/') {
471 if (!SWFDEC_IS_MOVIE (o
))
473 o
= SWFDEC_AS_OBJECT (swfdec_movie_get_root (SWFDEC_MOVIE (o
)));
478 for (start
= path
; path
< end
; path
++) {
479 if (dot_allowed
&& path
[0] == '.') {
480 if (end
- path
>= 2 && path
[1] == '.') {
484 } else if (path
[0] == ':') {
491 } else if (path
[0] == '/') {
493 } else if (path
- start
< 127) {
501 if (start
[0] == '.' && start
[1] == '.' && start
+ 2 == path
) {
502 /* ".." goes back to parent */
503 if (!SWFDEC_IS_MOVIE (o
))
505 o
= SWFDEC_AS_OBJECT (SWFDEC_MOVIE (o
)->parent
);
509 o
= super_special_movie_lookup_magic (o
, swfdec_as_context_give_string (cx
,
510 g_strndup (start
, path
- start
)));
514 if (path
- start
< 127)
522 * swfdec_action_get_movie_by_path:
523 * @cx: a #SwfdecAsContext
524 * @path: the path to look up
525 * @object: pointer that takes the object that was looked up. The object may be
527 * @variable: pointer that takes variable part of the path. The variable will
528 * be either %NULL or a non-gc'ed variable name.
530 * Looks up a Flash4-compatible path using "/", ":" and "." style syntax.
532 * Returns: The #SwfdecMovie that was looked up or %NULL if the path does not
533 * specify a valid movie.
536 swfdec_action_get_movie_by_path (SwfdecAsContext
*cx
, const char *path
,
537 SwfdecAsObject
**object
, const char **variable
)
539 SwfdecAsObject
*movie
;
542 g_assert (path
!= NULL
);
543 g_assert (object
!= NULL
);
544 g_assert (variable
!= NULL
);
545 g_assert (cx
->frame
!= NULL
);
547 /* find dot or colon */
548 end
= strpbrk (path
, ".:");
550 /* if no dot or colon, look up slash-path */
552 /* shortcut for the general case */
553 if (strchr (path
, '/') == NULL
) {
560 movie
= swfdec_action_get_movie_by_slash_path (cx
, path
);
569 /* find last dot or colon */
570 while ((s
= strpbrk (end
+ 1, ".:")) != NULL
)
573 /* variable to use is the part after the last dot or colon */
575 /* look up object for start of path */
576 movie
= swfdec_action_lookup_object (cx
, path
, end
);
587 swfdec_action_get_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
591 SwfdecAsObject
*object
;
593 val
= swfdec_as_stack_peek (cx
, 1);
594 s
= swfdec_as_value_to_string (cx
, val
);
595 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &s
)) {
598 swfdec_as_object_get_variable (object
, swfdec_as_context_get_string (cx
, s
), val
);
600 SWFDEC_AS_VALUE_SET_OBJECT (val
, object
);
603 swfdec_as_frame_get_variable (cx
->frame
, swfdec_as_context_get_string (cx
, s
), val
);
606 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
607 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
608 SWFDEC_WARNING ("no variable named %s", s
);
614 swfdec_action_set_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
618 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
619 swfdec_as_context_eval_set (cx
, NULL
, s
, swfdec_as_stack_peek (cx
, 1));
620 swfdec_as_stack_pop_n (cx
, 2);
624 swfdec_as_interpret_eval (SwfdecAsContext
*cx
, SwfdecAsObject
*obj
,
627 if (SWFDEC_AS_VALUE_IS_STRING (val
)) {
628 const char *s
= SWFDEC_AS_VALUE_GET_STRING (val
);
629 if (s
!= SWFDEC_AS_STR_EMPTY
) {
630 swfdec_as_context_eval (cx
, obj
, s
, val
);
635 SWFDEC_AS_VALUE_SET_OBJECT (val
, obj
);
637 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
638 return SWFDEC_AS_STR_EMPTY
;
641 /* FIXME: this sucks */
643 gboolean needs_movie
;
644 const char * name
; /* GC'd */
645 void (* get
) (SwfdecMovie
*movie
, SwfdecAsValue
*ret
);
646 void (* set
) (SwfdecMovie
*movie
, const SwfdecAsValue
*val
);
647 } swfdec_movieclip_props
[];
649 swfdec_action_get_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
655 id
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_pop (cx
));
656 if (id
> (cx
->version
> 4 ? 21 : 18)) {
657 SWFDEC_WARNING ("trying to SetProperty %u, not allowed", id
);
660 val
= swfdec_as_stack_peek (cx
, 1);
661 swfdec_as_interpret_eval (cx
, NULL
, val
);
662 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val
)) {
663 obj
= cx
->frame
->target
;
664 } else if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
665 obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
667 SWFDEC_WARNING ("not an object, can't GetProperty");
670 swfdec_as_object_get_variable (obj
, swfdec_movieclip_props
[id
].name
,
671 swfdec_as_stack_peek (cx
, 1));
675 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
679 swfdec_action_set_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
685 id
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
686 if (id
> (cx
->version
> 4 ? 21 : 18)) {
687 SWFDEC_WARNING ("trying to SetProperty %u, not allowed", id
);
690 val
= swfdec_as_stack_peek (cx
, 3);
691 swfdec_as_interpret_eval (cx
, NULL
, val
);
692 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val
)) {
693 obj
= cx
->frame
->target
;
694 } else if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
695 obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
697 SWFDEC_WARNING ("not an object, can't get SetProperty");
700 swfdec_as_object_set_variable (obj
, swfdec_movieclip_props
[id
].name
,
701 swfdec_as_stack_peek (cx
, 1));
703 swfdec_as_stack_pop_n (cx
, 3);
707 swfdec_action_get_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
709 SwfdecAsObject
*object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 2));
712 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
713 swfdec_as_object_get_variable (object
, name
, swfdec_as_stack_peek (cx
, 2));
714 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
715 if (SWFDEC_AS_VALUE_IS_UNDEFINED (swfdec_as_stack_peek (cx
, 2))) {
716 SWFDEC_WARNING ("no variable named %s:%s", G_OBJECT_TYPE_NAME (object
), name
);
720 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
722 swfdec_as_stack_pop (cx
);
726 swfdec_action_set_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
728 if (SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 3))) {
729 const char *name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
730 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 3)),
731 name
, swfdec_as_stack_peek (cx
, 1));
733 swfdec_as_stack_pop_n (cx
, 3);
737 swfdec_action_trace (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
742 val
= swfdec_as_stack_peek (cx
, 1);
743 if (val
->type
== SWFDEC_AS_TYPE_UNDEFINED
) {
744 s
= SWFDEC_AS_STR_undefined
;
745 } else if (val
->type
== SWFDEC_AS_TYPE_OBJECT
&&
746 SWFDEC_IS_AS_STRING (swfdec_as_value_to_object (cx
, val
))) {
747 s
= SWFDEC_AS_STRING (swfdec_as_value_to_object (cx
, val
))->string
;
749 s
= swfdec_as_value_to_string (cx
, val
);
751 swfdec_as_stack_pop (cx
);
752 g_signal_emit_by_name (cx
, "trace", s
);
755 /* stack looks like this: [ function, this, arg1, arg2, ... ] */
756 /* stack must be at least 2 elements big */
758 swfdec_action_call (SwfdecAsContext
*cx
, guint n_args
)
760 SwfdecAsFunction
*fun
;
761 SwfdecAsObject
*thisp
;
763 if (!SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 1)))
765 fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 1));
766 if (!SWFDEC_IS_AS_FUNCTION (fun
))
768 if (!SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 2))) {
771 thisp
= SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 2));
773 swfdec_as_stack_pop_n (cx
, 2);
774 /* sanitize argument count */
775 if (n_args
>= swfdec_as_stack_get_size (cx
))
776 n_args
= swfdec_as_stack_get_size (cx
);
777 swfdec_as_function_call (fun
, thisp
, n_args
, NULL
, NULL
);
778 if (SWFDEC_IS_AS_SUPER (fun
)) {
779 SWFDEC_LOG ("replacing super object on frame");
780 swfdec_as_super_replace (SWFDEC_AS_SUPER (fun
), NULL
);
786 if (n_args
> swfdec_as_stack_get_size (cx
))
787 n_args
= swfdec_as_stack_get_size (cx
);
788 swfdec_as_stack_pop_n (cx
, n_args
);
789 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
794 swfdec_action_call_function (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
796 SwfdecAsFrame
*frame
= cx
->frame
;
800 SwfdecAsValue
*fun
, *thisp
;
802 swfdec_as_stack_ensure_size (cx
, 2);
803 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
804 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
805 thisp
= swfdec_as_stack_peek (cx
, 2);
806 fun
= swfdec_as_stack_peek (cx
, 1);
807 obj
= swfdec_as_frame_get_variable (frame
, name
, fun
);
809 SWFDEC_AS_VALUE_SET_OBJECT (thisp
, obj
);
811 SWFDEC_AS_VALUE_SET_NULL (thisp
);
812 SWFDEC_AS_VALUE_SET_UNDEFINED (fun
);
814 if (!swfdec_action_call (cx
, n_args
)) {
815 SWFDEC_WARNING ("no function named %s", name
);
820 swfdec_action_call_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
822 SwfdecAsFrame
*frame
= cx
->frame
;
826 const char *name
= NULL
;
828 swfdec_as_stack_ensure_size (cx
, 3);
829 obj
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 2));
830 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
831 val
= swfdec_as_stack_peek (cx
, 1);
832 /* FIXME: this is a hack for constructors calling super - is this correct? */
833 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val
)) {
834 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
837 if (SWFDEC_AS_VALUE_IS_STRING (val
) &&
838 SWFDEC_AS_VALUE_GET_STRING (val
) == SWFDEC_AS_STR_EMPTY
) {
839 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 3));
840 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 2), obj
);
842 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 3), obj
);
843 name
= swfdec_as_value_to_string (cx
, val
);
844 swfdec_as_object_get_variable (obj
, name
, swfdec_as_stack_peek (cx
, 2));
847 if (SWFDEC_AS_VALUE_IS_STRING (val
))
848 name
= SWFDEC_AS_VALUE_GET_STRING (val
);
849 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_peek (cx
, 3));
850 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
852 swfdec_as_stack_pop (cx
);
853 if (swfdec_action_call (cx
, n_args
)) {
854 /* setup super to point to the right prototype */
856 if (SWFDEC_IS_AS_SUPER (obj
)) {
857 swfdec_as_super_replace (SWFDEC_AS_SUPER (obj
), name
);
858 } else if (frame
->super
) {
859 SwfdecAsSuper
*super
= SWFDEC_AS_SUPER (frame
->super
);
862 swfdec_as_object_get_variable_and_flags (frame
->thisp
,
863 name
, NULL
, NULL
, &super
->object
) &&
864 super
->object
== frame
->thisp
) {
865 super
->object
= super
->object
->prototype
;
869 SWFDEC_WARNING ("no function named %s on object %s", name
? name
: "unknown", obj
? G_OBJECT_TYPE_NAME(obj
) : "unknown");
874 swfdec_action_pop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
876 swfdec_as_stack_pop (cx
);
880 swfdec_action_binary (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
884 r
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
885 l
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
887 case SWFDEC_AS_ACTION_ADD
:
890 case SWFDEC_AS_ACTION_SUBTRACT
:
893 case SWFDEC_AS_ACTION_MULTIPLY
:
896 case SWFDEC_AS_ACTION_DIVIDE
:
897 if (cx
->version
< 5) {
899 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR__ERROR_
);
915 g_assert_not_reached ();
918 swfdec_as_stack_pop (cx
);
919 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), l
);
923 swfdec_action_add2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
925 SwfdecAsValue
*rval
, *lval
, rtmp
, ltmp
;
927 rval
= swfdec_as_stack_peek (cx
, 1);
928 lval
= swfdec_as_stack_peek (cx
, 2);
931 swfdec_as_value_to_primitive (&rtmp
);
932 if (!SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
) || SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
)))
934 swfdec_as_value_to_primitive (<mp
);
935 if (!SWFDEC_AS_VALUE_IS_OBJECT (<mp
) || SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (<mp
)))
938 if (SWFDEC_AS_VALUE_IS_STRING (lval
) || SWFDEC_AS_VALUE_IS_STRING (rval
)) {
939 const char *lstr
, *rstr
;
940 lstr
= swfdec_as_value_to_string (cx
, lval
);
941 rstr
= swfdec_as_value_to_string (cx
, rval
);
942 lstr
= swfdec_as_str_concat (cx
, lstr
, rstr
);
943 swfdec_as_stack_pop (cx
);
944 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), lstr
);
947 d
= swfdec_as_value_to_number (cx
, lval
);
948 d2
= swfdec_as_value_to_number (cx
, rval
);
950 swfdec_as_stack_pop (cx
);
951 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), d
);
956 swfdec_action_new_comparison (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
958 SwfdecAsValue
*lval
, *rval
;
961 rval
= swfdec_as_stack_peek (cx
, 1);
962 lval
= swfdec_as_stack_peek (cx
, 2);
964 /* swap if we do a greater comparison */
965 if (action
== SWFDEC_AS_ACTION_GREATER
) {
966 SwfdecAsValue
*tmp
= lval
;
970 /* comparison with object is always false */
971 swfdec_as_value_to_primitive (lval
);
972 if (SWFDEC_AS_VALUE_IS_OBJECT (lval
) &&
973 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (lval
))) {
974 swfdec_as_stack_pop (cx
);
975 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
978 /* same for the rval */
979 swfdec_as_value_to_primitive (rval
);
980 if (SWFDEC_AS_VALUE_IS_OBJECT (rval
) &&
981 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (rval
))) {
982 swfdec_as_stack_pop (cx
);
983 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
986 /* movieclips are not objects, but they evaluate to NaN, so we can handle them here */
987 if (SWFDEC_AS_VALUE_IS_OBJECT (rval
) ||
988 SWFDEC_AS_VALUE_IS_OBJECT (lval
)) {
989 swfdec_as_stack_pop (cx
);
990 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
993 /* if both are strings, compare strings */
994 if (SWFDEC_AS_VALUE_IS_STRING (rval
) &&
995 SWFDEC_AS_VALUE_IS_STRING (lval
)) {
996 const char *ls
= SWFDEC_AS_VALUE_GET_STRING (lval
);
997 const char *rs
= SWFDEC_AS_VALUE_GET_STRING (rval
);
999 if (ls
== SWFDEC_AS_STR_EMPTY
) {
1000 cmp
= rs
== SWFDEC_AS_STR_EMPTY
? 0 : 1;
1001 } else if (rs
== SWFDEC_AS_STR_EMPTY
) {
1004 cmp
= strcmp (ls
, rs
);
1006 swfdec_as_stack_pop (cx
);
1007 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cmp
< 0);
1010 /* convert to numbers and compare those */
1011 l
= swfdec_as_value_to_number (cx
, lval
);
1012 r
= swfdec_as_value_to_number (cx
, rval
);
1013 swfdec_as_stack_pop (cx
);
1014 /* NaN results in undefined */
1015 if (isnan (l
) || isnan (r
)) {
1016 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1019 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), l
< r
);
1023 swfdec_action_not_4 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1027 d
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1028 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), d
== 0 ? 1 : 0);
1032 swfdec_action_not_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1034 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1),
1035 !swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1)));
1039 swfdec_action_jump (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1042 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len
);
1045 cx
->frame
->pc
+= 5 + GINT16_FROM_LE (*((gint16
*) data
));
1049 swfdec_action_if (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1052 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len
);
1055 if (swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1)))
1056 cx
->frame
->pc
+= 5 + GINT16_FROM_LE (*((gint16
*) data
));
1057 swfdec_as_stack_pop (cx
);
1061 swfdec_action_decrement (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1065 val
= swfdec_as_stack_peek (cx
, 1);
1066 SWFDEC_AS_VALUE_SET_NUMBER (val
, swfdec_as_value_to_number (cx
, val
) - 1);
1070 swfdec_action_increment (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1074 val
= swfdec_as_stack_peek (cx
, 1);
1075 SWFDEC_AS_VALUE_SET_NUMBER (val
, swfdec_as_value_to_number (cx
, val
) + 1);
1079 swfdec_action_get_url (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1084 swfdec_bits_init_data (&bits
, data
, len
);
1085 url
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1086 target
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1087 if (url
== NULL
|| target
== NULL
) {
1088 SWFDEC_ERROR ("not enough data in GetURL");
1093 if (swfdec_bits_left (&bits
)) {
1094 SWFDEC_WARNING ("leftover bytes in GetURL action");
1096 if (SWFDEC_IS_MOVIE (cx
->frame
->target
))
1097 swfdec_movie_load (SWFDEC_MOVIE (cx
->frame
->target
), url
, target
,
1098 SWFDEC_LOADER_REQUEST_DEFAULT
, NULL
, 0);
1100 SWFDEC_WARNING ("no movie to load");
1106 swfdec_action_get_url2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1108 const char *target
, *url
;
1112 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
1116 target
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1117 url
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1118 method
= data
[0] & 3;
1121 SWFDEC_ERROR ("GetURL method 3 invalid");
1125 if (data
[0] & 128 && data
[0] & 64) {
1126 if (SWFDEC_IS_MOVIE (cx
->frame
->target
)) {
1127 swfdec_movie_load_variables (SWFDEC_MOVIE (cx
->frame
->target
), url
,
1130 SWFDEC_WARNING ("no movie to load");
1132 } else if (data
[0] & 128) {
1133 SWFDEC_FIXME ("LoadVariables without LoadTarget?");
1136 SWFDEC_FIXME ("implement LoadTarget");
1137 if (SWFDEC_IS_MOVIE (cx
->frame
->target
)) {
1138 swfdec_movie_load (SWFDEC_MOVIE (cx
->frame
->target
), url
, target
, method
,
1141 SWFDEC_WARNING ("no movie to load");
1145 swfdec_as_stack_pop_n (cx
, 2);
1149 swfdec_action_string_add (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1151 const char *lval
, *rval
;
1153 rval
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1154 lval
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1155 lval
= swfdec_as_str_concat (cx
, lval
, rval
);
1156 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 2), lval
);
1157 swfdec_as_stack_pop (cx
);
1161 swfdec_action_push_duplicate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1163 *swfdec_as_stack_push (cx
) = *swfdec_as_stack_peek (cx
, 1);
1167 swfdec_action_random_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1172 val
= swfdec_as_stack_peek (cx
, 1);
1173 max
= swfdec_as_value_to_integer (cx
, val
);
1176 SWFDEC_AS_VALUE_SET_NUMBER (val
, 0);
1178 SWFDEC_AS_VALUE_SET_NUMBER (val
, g_rand_int_range (cx
->rand
, 0, max
));
1182 swfdec_action_old_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1187 l
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
1188 r
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1190 case SWFDEC_AS_ACTION_EQUALS
:
1193 case SWFDEC_AS_ACTION_LESS
:
1197 g_assert_not_reached ();
1200 swfdec_as_stack_pop (cx
);
1201 if (cx
->version
< 5) {
1202 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), cond
? 1 : 0);
1204 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1209 swfdec_action_string_length (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1214 v
= swfdec_as_stack_peek (cx
, 1);
1215 s
= swfdec_as_value_to_string (cx
, v
);
1216 SWFDEC_AS_VALUE_SET_INT (v
, g_utf8_strlen (s
, -1));
1220 swfdec_action_string_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1225 r
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1226 l
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1228 case SWFDEC_AS_ACTION_STRING_EQUALS
:
1231 case SWFDEC_AS_ACTION_STRING_LESS
:
1232 cond
= strcmp (l
, r
) < 0;
1235 g_assert_not_reached ();
1238 swfdec_as_stack_pop (cx
);
1239 if (cx
->version
< 5) {
1240 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), cond
? 1 : 0);
1242 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1247 swfdec_action_equals2_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1249 SwfdecAsValue
*rval
, *lval
;
1250 SwfdecAsValue rtmp
, ltmp
;
1251 SwfdecAsValueType ltype
, rtype
;
1255 rval
= swfdec_as_stack_peek (cx
, 1);
1256 lval
= swfdec_as_stack_peek (cx
, 2);
1259 swfdec_as_value_to_primitive (&rtmp
);
1260 swfdec_as_value_to_primitive (<mp
);
1264 /* get objects compared */
1265 if (ltype
== SWFDEC_AS_TYPE_OBJECT
&& rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1266 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (<mp
);
1267 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
);
1269 if (!SWFDEC_IS_MOVIE (lo
))
1270 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1271 if (!SWFDEC_IS_MOVIE (ro
))
1272 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1274 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1276 } else if (SWFDEC_IS_MOVIE (lo
)) {
1277 swfdec_as_value_to_primitive (rval
);
1279 if (rtype
!= SWFDEC_AS_TYPE_OBJECT
) {
1283 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1284 } else if (SWFDEC_IS_MOVIE (ro
)) {
1285 swfdec_as_value_to_primitive (lval
);
1287 if (ltype
!= SWFDEC_AS_TYPE_OBJECT
) {
1291 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1297 /* compare strings */
1298 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1299 /* FIXME: flash 5 case insensitive? */
1300 cond
= SWFDEC_AS_VALUE_GET_STRING (<mp
) == SWFDEC_AS_VALUE_GET_STRING (&rtmp
);
1304 /* convert to numbers */
1305 if (SWFDEC_AS_VALUE_IS_OBJECT (<mp
) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (<mp
))) {
1306 l
= swfdec_as_value_to_number (cx
, lval
);
1308 l
= swfdec_as_value_to_number (cx
, <mp
);
1310 if (SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
))) {
1311 r
= swfdec_as_value_to_number (cx
, rval
);
1313 r
= swfdec_as_value_to_number (cx
, &rtmp
);
1316 /* get rid of undefined and null */
1317 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1318 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1325 /* else compare as numbers */
1326 if (isnan (l
) && isnan (r
))
1327 cond
= ltype
== rtype
;
1332 swfdec_as_stack_pop (cx
);
1333 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1337 swfdec_action_equals2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1339 SwfdecAsValue
*rval
, *lval
;
1340 SwfdecAsValueType ltype
, rtype
;
1344 rval
= swfdec_as_stack_peek (cx
, 1);
1345 lval
= swfdec_as_stack_peek (cx
, 2);
1349 /* get objects compared */
1350 if (ltype
== SWFDEC_AS_TYPE_OBJECT
&& rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1351 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1352 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1354 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1356 } else if (SWFDEC_IS_MOVIE (lo
)) {
1357 swfdec_as_value_to_primitive (rval
);
1359 if (rtype
!= SWFDEC_AS_TYPE_OBJECT
) {
1363 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1364 } else if (SWFDEC_IS_MOVIE (ro
)) {
1365 swfdec_as_value_to_primitive (lval
);
1367 if (ltype
!= SWFDEC_AS_TYPE_OBJECT
) {
1371 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1377 /* if one of the values is an object, call valueOf.
1378 * If it's still an object, return FALSE */
1379 swfdec_as_value_to_primitive (lval
);
1381 if (ltype
== SWFDEC_AS_TYPE_OBJECT
) {
1385 swfdec_as_value_to_primitive (rval
);
1387 if (rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1391 /* now we have a comparison without objects */
1393 /* get rid of undefined and null */
1394 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1395 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1402 /* compare strings */
1403 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1404 /* FIXME: flash 5 case insensitive? */
1405 cond
= SWFDEC_AS_VALUE_GET_STRING (lval
) == SWFDEC_AS_VALUE_GET_STRING (rval
);
1409 /* else compare as numbers */
1410 l
= swfdec_as_value_to_number (cx
, lval
);
1411 r
= swfdec_as_value_to_number (cx
, rval
);
1413 if (isnan (l
) && isnan (r
))
1414 cond
= ltype
== rtype
;
1419 swfdec_as_stack_pop (cx
);
1420 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1424 swfdec_action_strict_equals (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1426 SwfdecAsValue
*rval
, *lval
;
1429 rval
= swfdec_as_stack_peek (cx
, 1);
1430 lval
= swfdec_as_stack_peek (cx
, 2);
1432 if (rval
->type
!= lval
->type
) {
1435 switch (rval
->type
) {
1436 case SWFDEC_AS_TYPE_UNDEFINED
:
1437 case SWFDEC_AS_TYPE_NULL
:
1440 case SWFDEC_AS_TYPE_BOOLEAN
:
1441 cond
= SWFDEC_AS_VALUE_GET_BOOLEAN (rval
) == SWFDEC_AS_VALUE_GET_BOOLEAN (lval
);
1443 case SWFDEC_AS_TYPE_NUMBER
:
1446 r
= SWFDEC_AS_VALUE_GET_NUMBER (rval
);
1447 l
= SWFDEC_AS_VALUE_GET_NUMBER (lval
);
1448 cond
= (l
== r
) || (isnan (l
) && isnan (r
));
1451 case SWFDEC_AS_TYPE_STRING
:
1452 cond
= SWFDEC_AS_VALUE_GET_STRING (rval
) == SWFDEC_AS_VALUE_GET_STRING (lval
);
1454 case SWFDEC_AS_TYPE_OBJECT
:
1455 cond
= SWFDEC_AS_VALUE_GET_OBJECT (rval
) == SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1458 g_assert_not_reached ();
1463 swfdec_as_stack_pop (cx
);
1464 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1468 swfdec_action_set_target (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1470 if (!memchr (data
, 0, len
)) {
1471 SWFDEC_ERROR ("SetTarget action does not specify a string");
1474 if (*data
== '\0') {
1475 swfdec_as_frame_set_target (cx
->frame
, NULL
);
1477 SwfdecAsValue target
;
1478 swfdec_as_context_eval (cx
, NULL
, (const char *) data
, &target
);
1479 if (!SWFDEC_AS_VALUE_IS_OBJECT (&target
)) {
1480 SWFDEC_WARNING ("target is not an object");
1483 /* FIXME: allow non-movieclips as targets? */
1484 swfdec_as_frame_set_target (cx
->frame
, SWFDEC_AS_VALUE_GET_OBJECT (&target
));
1489 swfdec_action_set_target2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1492 val
= swfdec_as_stack_peek (cx
, 1);
1493 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
1494 SWFDEC_WARNING ("target is not an object");
1496 /* FIXME: allow non-movieclips as targets? */
1497 swfdec_as_frame_set_target (cx
->frame
, SWFDEC_AS_VALUE_GET_OBJECT (val
));
1499 swfdec_as_stack_pop (cx
);
1503 swfdec_action_start_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1505 SwfdecRect rect
, *rectp
= NULL
;
1508 guint stack_size
= 3;
1510 swfdec_as_stack_ensure_size (cx
, 3);
1511 if (swfdec_as_interpret_eval (cx
, NULL
, swfdec_as_stack_peek (cx
, 1)) == SWFDEC_AS_STR_EMPTY
) {
1512 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 1), cx
->frame
->target
);
1514 center
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
1515 if (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 3))) {
1516 swfdec_as_stack_ensure_size (cx
, 7);
1517 rect
.x0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 7));
1518 rect
.y0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 6));
1519 rect
.x1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 5));
1520 rect
.y1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 4));
1521 swfdec_rect_scale (&rect
, &rect
, SWFDEC_TWIPS_SCALE_FACTOR
);
1525 if (SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 1)) &&
1526 SWFDEC_IS_MOVIE (movie
= (SwfdecMovie
*) SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 1)))) {
1527 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), movie
, center
, &rect
);
1529 SWFDEC_ERROR ("startDrag on something not a Movie");
1531 swfdec_as_stack_pop_n (cx
, stack_size
);
1535 swfdec_action_end_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1537 if (SWFDEC_IS_PLAYER (cx
)) {
1538 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), NULL
, FALSE
, NULL
);
1540 SWFDEC_WARNING ("can't end a drag on non-players");
1545 swfdec_action_stop_sounds (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1547 if (SWFDEC_IS_PLAYER (cx
)) {
1548 swfdec_player_stop_all_sounds (SWFDEC_PLAYER (cx
));
1553 swfdec_action_new_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1555 SwfdecAsValue
*constructor
;
1556 SwfdecAsFunction
*fun
;
1560 swfdec_as_stack_ensure_size (cx
, 2);
1561 constructor
= swfdec_as_stack_peek (cx
, 1);
1562 name
= swfdec_as_interpret_eval (cx
, NULL
, constructor
);
1563 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1564 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 2, n_args
);
1565 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1566 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
))) {
1567 SWFDEC_WARNING ("%s is not a constructor", name
);
1571 swfdec_as_stack_pop_n (cx
, 2);
1572 swfdec_as_object_create (fun
, n_args
, NULL
);
1576 swfdec_as_stack_pop_n (cx
, n_args
+ 1);
1577 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1581 swfdec_action_new_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1583 SwfdecAsValue
*constructor
;
1584 SwfdecAsFunction
*fun
;
1588 swfdec_as_stack_ensure_size (cx
, 3);
1589 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1591 constructor
= swfdec_as_stack_peek (cx
, 2);
1592 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
1593 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 3, n_args
);
1594 if (name
!= SWFDEC_AS_STR_EMPTY
) {
1595 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
)) {
1596 SWFDEC_WARNING ("NewMethod called without an object to get variable %s from", name
);
1599 swfdec_as_object_get_variable (SWFDEC_AS_VALUE_GET_OBJECT (constructor
),
1602 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1603 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
))) {
1604 SWFDEC_WARNING ("%s is not a constructor", name
);
1608 swfdec_as_stack_pop_n (cx
, 3);
1609 swfdec_as_object_create (fun
, n_args
, NULL
);
1613 swfdec_as_stack_pop_n (cx
, n_args
+ 2);
1614 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1618 swfdec_action_init_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1620 SwfdecAsObject
*object
;
1621 guint i
, n_args
, size
;
1623 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1624 swfdec_as_stack_pop (cx
);
1625 if (n_args
* 2 > swfdec_as_stack_get_size (cx
)) {
1626 size
= swfdec_as_stack_get_size (cx
);
1627 SWFDEC_FIXME ("InitObject action with too small stack, help!");
1634 object
= swfdec_as_object_new (cx
);
1637 for (i
= 0; i
< n_args
; i
++) {
1638 const char *s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1639 swfdec_as_object_set_variable (object
, s
, swfdec_as_stack_peek (cx
, 1));
1640 swfdec_as_stack_pop_n (cx
, 2);
1642 swfdec_as_stack_pop_n (cx
, size
);
1643 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
1647 swfdec_action_init_array (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1650 SwfdecAsObject
*array
;
1652 swfdec_as_stack_ensure_size (cx
, 1);
1653 n
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1654 swfdec_as_stack_pop (cx
);
1655 array
= swfdec_as_array_new (cx
);
1658 /* NB: we can't increase the stack here, as the number can easily be MAXINT */
1659 for (i
= 0; i
< n
&& swfdec_as_stack_get_size (cx
) > 0; i
++) {
1660 swfdec_as_stack_ensure_size (cx
, 1);
1661 swfdec_as_array_push (SWFDEC_AS_ARRAY (array
), swfdec_as_stack_pop (cx
));
1665 SWFDEC_AS_VALUE_SET_INT (&val
, i
);
1666 swfdec_as_object_set_variable (array
, SWFDEC_AS_STR_length
, &val
);
1668 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), array
);
1672 swfdec_action_define_function (SwfdecAsContext
*cx
, guint action
,
1673 const guint8
*data
, guint len
)
1675 char *function_name
;
1676 const char *name
= NULL
;
1677 guint i
, n_args
, size
, n_registers
;
1678 SwfdecBuffer
*buffer
;
1680 SwfdecAsFunction
*fun
;
1681 SwfdecAsFrame
*frame
;
1682 SwfdecScript
*script
;
1684 SwfdecScriptArgument
*args
;
1685 gboolean v2
= (action
== 0x8e);
1688 swfdec_bits_init_data (&bits
, data
, len
);
1689 function_name
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1690 if (function_name
== NULL
) {
1691 SWFDEC_ERROR ("could not parse function name");
1694 n_args
= swfdec_bits_get_u16 (&bits
);
1696 n_registers
= swfdec_bits_get_u8 (&bits
);
1697 if (n_registers
== 0)
1699 flags
= swfdec_bits_get_u16 (&bits
);
1704 args
= g_new0 (SwfdecScriptArgument
, n_args
);
1705 for (i
= 0; i
< n_args
&& swfdec_bits_left (&bits
); i
++) {
1707 args
[i
].preload
= swfdec_bits_get_u8 (&bits
);
1708 if (args
[i
].preload
&& args
[i
].preload
>= n_registers
) {
1709 SWFDEC_ERROR ("argument %u cannot be preloaded into register %u out of %u",
1710 i
, args
[i
].preload
, n_registers
);
1711 /* FIXME: figure out correct error handling here */
1712 args
[i
].preload
= 0;
1715 args
[i
].name
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1716 if (args
[i
].name
== NULL
|| args
[i
].name
== '\0') {
1717 SWFDEC_ERROR ("empty argument name not allowed");
1721 /* FIXME: check duplicate arguments */
1726 size
= swfdec_bits_get_u16 (&bits
);
1727 /* check the script can be created */
1728 if (frame
->script
->buffer
->data
+ frame
->script
->buffer
->length
< frame
->pc
+ 3 + len
+ size
) {
1729 SWFDEC_ERROR ("size of function is too big");
1731 g_free (function_name
);
1734 /* create the script */
1735 buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
1736 frame
->pc
+ 3 + len
- frame
->script
->buffer
->data
, size
);
1737 swfdec_bits_init (&bits
, buffer
);
1738 if (*function_name
) {
1739 name
= function_name
;
1740 } else if (swfdec_as_stack_get_size (cx
) > 0) {
1741 /* This is kind of a hack that uses a feature of the Adobe compiler:
1742 * foo = function () {} is compiled as these actions:
1743 * Push "foo", DefineFunction, SetVariable/SetMember
1744 * With this knowledge we can inspect the topmost stack member, since
1745 * it will contain the name this function will soon be assigned to.
1747 if (SWFDEC_AS_VALUE_IS_STRING (swfdec_as_stack_peek (cx
, 1)))
1748 name
= SWFDEC_AS_VALUE_GET_STRING (swfdec_as_stack_peek (cx
, 1));
1751 name
= "unnamed_function";
1752 script
= swfdec_script_new_from_bits (&bits
, name
, cx
->version
);
1753 swfdec_buffer_unref (buffer
);
1754 if (script
== NULL
) {
1755 SWFDEC_ERROR ("failed to create script");
1757 g_free (function_name
);
1760 if (frame
->constant_pool_buffer
)
1761 script
->constant_pool
= swfdec_buffer_ref (frame
->constant_pool_buffer
);
1762 script
->flags
= flags
;
1763 script
->n_registers
= n_registers
;
1764 script
->n_arguments
= n_args
;
1765 script
->arguments
= args
;
1766 /* see function-scope tests */
1767 if (cx
->version
> 5) {
1768 /* FIXME: or original target? */
1769 fun
= swfdec_as_script_function_new (frame
->target
, frame
->scope_chain
, script
);
1771 fun
= swfdec_as_script_function_new (frame
->target
, NULL
, script
);
1775 /* attach the function */
1776 if (*function_name
== '\0') {
1777 swfdec_as_stack_ensure_free (cx
, 1);
1778 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), SWFDEC_AS_OBJECT (fun
));
1780 SwfdecAsValue funval
;
1781 /* FIXME: really varobj? Not eval or sth like that? */
1782 name
= swfdec_as_context_get_string (cx
, function_name
);
1783 SWFDEC_AS_VALUE_SET_OBJECT (&funval
, SWFDEC_AS_OBJECT (fun
));
1784 swfdec_as_object_set_variable (frame
->target
, name
, &funval
);
1787 /* update current context */
1788 frame
->pc
+= 3 + len
+ size
;
1789 g_free (function_name
);
1793 swfdec_action_bitwise (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1797 a
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1798 b
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1811 g_assert_not_reached ();
1815 swfdec_as_stack_pop (cx
);
1816 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_peek (cx
, 1), a
);
1820 swfdec_action_shift (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1824 amount
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1826 value
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1830 value
= value
<< amount
;
1833 value
= ((gint
) value
) >> amount
;
1836 value
= ((guint
) value
) >> amount
;
1839 g_assert_not_reached ();
1842 swfdec_as_stack_pop (cx
);
1843 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_peek (cx
, 1), value
);
1847 swfdec_action_to_integer (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1849 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
1851 SWFDEC_AS_VALUE_SET_INT (val
, swfdec_as_value_to_integer (cx
, val
));
1855 swfdec_action_target_path (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1861 val
= swfdec_as_stack_peek (cx
, 1);
1863 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
) ||
1864 !SWFDEC_IS_MOVIE (movie
= (SwfdecMovie
*) SWFDEC_AS_VALUE_GET_OBJECT (val
))) {
1865 SWFDEC_FIXME ("What's the TargetPath for non-movies?");
1866 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
1869 s
= swfdec_movie_get_path (movie
);
1870 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_give_string (cx
, s
));
1874 swfdec_action_define_local (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1876 SwfdecAsObject
*target
;
1879 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1880 if (cx
->frame
->is_local
) {
1881 target
= SWFDEC_AS_OBJECT (cx
->frame
);
1883 target
= cx
->frame
->target
;
1885 swfdec_as_object_set_variable (target
, name
,
1886 swfdec_as_stack_peek (cx
, 1));
1887 swfdec_as_stack_pop_n (cx
, 2);
1891 swfdec_action_define_local2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1893 SwfdecAsValue val
= { 0, };
1894 SwfdecAsObject
*target
;
1897 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1898 if (cx
->frame
->is_local
) {
1899 target
= SWFDEC_AS_OBJECT (cx
->frame
);
1901 target
= cx
->frame
->target
;
1903 swfdec_as_object_set_variable (target
, name
, &val
);
1904 swfdec_as_stack_pop (cx
);
1908 swfdec_action_return (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1910 swfdec_as_frame_return (cx
->frame
, swfdec_as_stack_pop (cx
));
1914 swfdec_action_delete (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1918 gboolean success
= FALSE
;
1920 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1921 val
= swfdec_as_stack_peek (cx
, 2);
1922 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
1923 success
= swfdec_as_object_delete_variable (
1924 SWFDEC_AS_VALUE_GET_OBJECT (val
), name
) == SWFDEC_AS_DELETE_DELETED
;
1926 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
1927 swfdec_as_stack_pop_n (cx
, 1);
1931 swfdec_action_delete2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1935 gboolean success
= FALSE
;
1937 val
= swfdec_as_stack_peek (cx
, 1);
1938 name
= swfdec_as_value_to_string (cx
, val
);
1939 success
= swfdec_as_frame_delete_variable (cx
->frame
, name
) == SWFDEC_AS_DELETE_DELETED
;
1940 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
1944 swfdec_action_store_register (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1947 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
1950 if (!swfdec_action_has_register (cx
, *data
)) {
1951 SWFDEC_ERROR ("Cannot store into register %u, not enough registers", (guint
) *data
);
1954 cx
->frame
->registers
[*data
] = *swfdec_as_stack_peek (cx
, 1);
1958 swfdec_action_modulo (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1962 y
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1963 x
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
1964 /* yay, we're portable! */
1971 SWFDEC_FIXME ("errno set after fmod");
1974 swfdec_as_stack_pop (cx
);
1975 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), x
);
1979 swfdec_action_swap (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1981 swfdec_as_stack_swap (cx
, 1, 2);
1985 swfdec_action_to_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1987 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1),
1988 swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)));
1992 swfdec_action_to_string (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1994 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
1995 swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1)));
1999 swfdec_action_type_of (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2004 val
= swfdec_as_stack_peek (cx
, 1);
2005 switch (val
->type
) {
2006 case SWFDEC_AS_TYPE_NUMBER
:
2007 type
= SWFDEC_AS_STR_number
;
2009 case SWFDEC_AS_TYPE_BOOLEAN
:
2010 type
= SWFDEC_AS_STR_boolean
;
2012 case SWFDEC_AS_TYPE_STRING
:
2013 type
= SWFDEC_AS_STR_string
;
2015 case SWFDEC_AS_TYPE_UNDEFINED
:
2016 type
= SWFDEC_AS_STR_undefined
;
2018 case SWFDEC_AS_TYPE_NULL
:
2019 type
= SWFDEC_AS_STR_null
;
2021 case SWFDEC_AS_TYPE_OBJECT
:
2023 SwfdecAsObject
*obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2024 if (SWFDEC_IS_MOVIE (obj
)) {
2025 type
= SWFDEC_AS_STR_movieclip
;
2026 } else if (SWFDEC_IS_AS_FUNCTION (obj
)) {
2027 type
= SWFDEC_AS_STR_function
;
2029 type
= SWFDEC_AS_STR_object
;
2034 g_assert_not_reached ();
2035 type
= SWFDEC_AS_STR_EMPTY
;
2038 SWFDEC_AS_VALUE_SET_STRING (val
, type
);
2042 swfdec_action_get_time (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2047 swfdec_as_context_get_time (cx
, &tv
);
2048 /* we assume here that swfdec_as_context_get_time always returns a tv > start_time */
2049 diff
= tv
.tv_sec
- cx
->start_time
.tv_sec
;
2050 if (diff
> G_MAXULONG
/ 1000 - 1) {
2051 SWFDEC_ERROR ("FIXME: time overflow");
2054 diff
= diff
+ (tv
.tv_usec
- cx
->start_time
.tv_usec
) / 1000;
2056 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_push (cx
), diff
);
2060 swfdec_action_extends (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2062 SwfdecAsValue
*superclass
, *subclass
, proto
;
2063 SwfdecAsObject
*prototype
;
2064 SwfdecAsObject
*super
;
2066 superclass
= swfdec_as_stack_peek (cx
, 1);
2067 subclass
= swfdec_as_stack_peek (cx
, 2);
2068 if (!SWFDEC_AS_VALUE_IS_OBJECT (superclass
) ||
2069 !SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (superclass
))) {
2070 SWFDEC_ERROR ("superclass is not a function");
2073 if (!SWFDEC_AS_VALUE_IS_OBJECT (subclass
)) {
2074 SWFDEC_ERROR ("subclass is not an object");
2077 super
= SWFDEC_AS_VALUE_GET_OBJECT (superclass
);
2078 prototype
= swfdec_as_object_new_empty (cx
);
2079 if (prototype
== NULL
)
2081 swfdec_as_object_get_variable (super
, SWFDEC_AS_STR_prototype
, &proto
);
2082 swfdec_as_object_set_variable (prototype
, SWFDEC_AS_STR___proto__
, &proto
);
2083 if (cx
->version
> 5) {
2084 swfdec_as_object_set_variable_and_flags (prototype
, SWFDEC_AS_STR___constructor__
,
2085 superclass
, SWFDEC_AS_VARIABLE_HIDDEN
);
2087 SWFDEC_AS_VALUE_SET_OBJECT (&proto
, prototype
);
2088 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_OBJECT (subclass
),
2089 SWFDEC_AS_STR_prototype
, &proto
);
2091 swfdec_as_stack_pop_n (cx
, 2);
2095 swfdec_action_enumerate_foreach (SwfdecAsObject
*object
, const char *variable
,
2096 SwfdecAsValue
*value
, guint flags
, gpointer listp
)
2098 GSList
**list
= listp
;
2100 if (flags
& SWFDEC_AS_VARIABLE_HIDDEN
)
2103 *list
= g_slist_remove (*list
, variable
);
2104 *list
= g_slist_prepend (*list
, (gpointer
) variable
);
2109 swfdec_action_do_enumerate (SwfdecAsContext
*cx
, SwfdecAsObject
*object
)
2112 GSList
*walk
, *list
= NULL
;
2114 for (i
= 0; i
< 256 && object
; i
++) {
2115 swfdec_as_object_foreach (object
, swfdec_action_enumerate_foreach
, &list
);
2116 object
= object
->prototype
;
2119 swfdec_as_context_abort (object
->context
, "Prototype recursion limit exceeded");
2120 g_slist_free (list
);
2123 list
= g_slist_reverse (list
);
2125 for (walk
= list
; walk
; walk
= walk
->next
) {
2126 /* 8 is an arbitrary value */
2128 swfdec_as_stack_ensure_free (cx
, 8);
2132 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
), walk
->data
);
2134 g_slist_free (list
);
2138 swfdec_action_enumerate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2141 SwfdecAsObject
*obj
;
2143 val
= swfdec_as_stack_peek (cx
, 1);
2145 swfdec_as_interpret_eval (cx
, NULL
, val
);
2146 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2147 SWFDEC_ERROR ("Enumerate not pointing to an object");
2148 SWFDEC_AS_VALUE_SET_NULL (val
);
2151 obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2152 SWFDEC_AS_VALUE_SET_NULL (val
);
2153 swfdec_action_do_enumerate (cx
, obj
);
2157 swfdec_action_enumerate2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2160 SwfdecAsObject
*obj
;
2162 val
= swfdec_as_stack_peek (cx
, 1);
2163 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2164 SWFDEC_ERROR ("Enumerate2 called without an object");
2165 SWFDEC_AS_VALUE_SET_NULL (val
);
2168 obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2169 SWFDEC_AS_VALUE_SET_NULL (val
);
2170 swfdec_action_do_enumerate (cx
, obj
);
2174 swfdec_action_logical (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2179 l
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1));
2180 val
= swfdec_as_stack_peek (cx
, 2);
2181 r
= swfdec_as_value_to_boolean (cx
, val
);
2183 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, (action
== 0x10) ? (l
&& r
) : (l
|| r
));
2184 swfdec_as_stack_pop (cx
);
2188 swfdec_action_char_to_ascii_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2190 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2191 const char *s
= swfdec_as_value_to_string (cx
, val
);
2194 ascii
= g_convert (s
, -1, "LATIN1", "UTF-8", NULL
, NULL
, NULL
);
2195 if (ascii
== NULL
) {
2196 /* This can happen if a Flash 5 movie gets loaded into a Flash 7 movie */
2197 SWFDEC_FIXME ("Someone threw unconvertible text %s at Flash <= 5", s
);
2198 SWFDEC_AS_VALUE_SET_INT (val
, 0); /* FIXME: what to return??? */
2200 SWFDEC_AS_VALUE_SET_INT (val
, (guchar
) ascii
[0]);
2206 swfdec_action_char_to_ascii (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2208 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2209 const char *s
= swfdec_as_value_to_string(cx
, val
);
2212 uni
= g_utf8_to_ucs4_fast (s
, -1, NULL
);
2214 /* This should never happen, everything is valid UTF-8 in here */
2215 g_warning ("conversion of character %s failed", s
);
2216 SWFDEC_AS_VALUE_SET_INT (val
, 0);
2218 SWFDEC_AS_VALUE_SET_INT (val
, uni
[0]);
2224 swfdec_action_ascii_to_char (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2227 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2228 gunichar c
= ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 65536;
2230 s
= g_ucs4_to_utf8 (&c
, 1, NULL
, NULL
, NULL
);
2232 g_warning ("conversion of character %u failed", (guint
) c
);
2233 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2235 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, s
));
2241 swfdec_action_ascii_to_char_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2243 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2247 s
[0] = ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 256;
2250 utf8
= g_convert (s
, -1, "UTF-8", "LATIN1", NULL
, NULL
, NULL
);
2252 g_warning ("conversion of character %u failed", (guint
) s
[0]);
2253 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2255 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, utf8
));
2261 swfdec_action_mb_ascii_to_char_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2263 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2268 i
= ((guint
) swfdec_as_value_to_integer (cx
, val
));
2277 utf8
= g_convert (s
, -1, "UTF-8", "LATIN1", NULL
, NULL
, NULL
);
2279 g_warning ("conversion of character %u failed", i
);
2280 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2282 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, utf8
));
2288 swfdec_action_pop_with (SwfdecAsFrame
*frame
, gpointer with_object
)
2290 g_assert (frame
->scope_chain
->data
== with_object
);
2291 frame
->scope_chain
= g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2292 swfdec_as_frame_pop_block (frame
);
2296 swfdec_action_with (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2298 SwfdecAsObject
*object
;
2302 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2303 swfdec_as_stack_pop (cx
);
2306 offset
= data
[0] | (data
[1] << 8);
2307 object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 1));
2308 if (object
== NULL
) {
2309 SWFDEC_INFO ("With called without an object, skipping");
2310 cx
->frame
->pc
= (guint8
*) data
+ len
+ offset
;
2312 cx
->frame
->scope_chain
= g_slist_prepend (cx
->frame
->scope_chain
, object
);
2313 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ offset
,
2314 swfdec_action_pop_with
, object
, NULL
);
2316 swfdec_as_stack_pop (cx
);
2320 swfdec_action_remove_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2322 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2323 SwfdecAsObject
*sprite
;
2326 if (SWFDEC_AS_VALUE_IS_STRING (val
)) {
2327 const char *name
= SWFDEC_AS_VALUE_GET_STRING (val
);
2329 swfdec_as_context_eval (cx
, NULL
, name
, val
);
2331 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2332 sprite
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2334 SWFDEC_FIXME ("unknown type in RemoveSprite");
2337 if (!SWFDEC_IS_MOVIE (sprite
)) {
2338 SWFDEC_FIXME ("cannot remove non movieclip objects");
2341 movie
= SWFDEC_MOVIE (sprite
);
2342 if (swfdec_depth_classify (movie
->depth
) == SWFDEC_DEPTH_CLASS_DYNAMIC
) {
2343 SWFDEC_LOG ("removing clip %s", movie
->name
);
2344 swfdec_movie_remove (movie
);
2347 swfdec_as_stack_pop (cx
);
2351 swfdec_action_clone_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2353 SwfdecMovie
*movie
, *new_movie
;
2354 SwfdecAsObject
*obj
;
2355 const char *new_name
;
2358 depth
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1)) - 16384;
2359 new_name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
2360 if (SWFDEC_AS_VALUE_IS_STRING (swfdec_as_stack_peek (cx
, 3))) {
2362 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 3));
2363 swfdec_as_context_eval (cx
, NULL
, name
, swfdec_as_stack_peek (cx
, 3));
2365 obj
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 3));
2366 if (!SWFDEC_IS_MOVIE(obj
)) {
2367 SWFDEC_ERROR ("Object is not an SwfdecMovie object");
2368 swfdec_as_stack_pop_n (cx
, 3);
2371 movie
= SWFDEC_MOVIE(obj
);
2372 new_movie
= swfdec_movie_duplicate (movie
, new_name
, depth
);
2374 SWFDEC_LOG ("duplicated %s as %s to depth %u", movie
->name
, new_movie
->name
, new_movie
->depth
);
2375 if (SWFDEC_IS_SPRITE_MOVIE (new_movie
)) {
2376 g_queue_push_tail (SWFDEC_PLAYER (cx
)->init_queue
, new_movie
);
2377 swfdec_movie_queue_script (new_movie
, SWFDEC_EVENT_LOAD
);
2378 swfdec_movie_run_construct (new_movie
);
2380 swfdec_movie_initialize (new_movie
);
2382 swfdec_as_stack_pop_n (cx
, 3);
2385 /*** PRINT FUNCTIONS ***/
2388 swfdec_action_print_with (guint action
, const guint8
*data
, guint len
)
2391 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2394 return g_strdup_printf ("With %u", data
[0] | (data
[1] << 8));
2398 swfdec_action_print_store_register (guint action
, const guint8
*data
, guint len
)
2401 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
2404 return g_strdup_printf ("StoreRegister %u", (guint
) *data
);
2408 swfdec_action_print_set_target (guint action
, const guint8
*data
, guint len
)
2410 if (!memchr (data
, 0, len
)) {
2411 SWFDEC_ERROR ("SetTarget action does not specify a string");
2414 return g_strconcat ("SetTarget ", data
, NULL
);
2418 swfdec_action_print_define_function (guint action
, const guint8
*data
, guint len
)
2422 const char *function_name
;
2423 guint i
, n_args
, size
;
2424 gboolean v2
= (action
== 0x8e);
2426 string
= g_string_new (v2
? "DefineFunction2 " : "DefineFunction ");
2427 swfdec_bits_init_data (&bits
, data
, len
);
2428 function_name
= swfdec_bits_get_string (&bits
);
2429 if (function_name
== NULL
) {
2430 SWFDEC_ERROR ("could not parse function name");
2431 g_string_free (string
, TRUE
);
2434 if (*function_name
) {
2435 g_string_append (string
, function_name
);
2436 g_string_append_c (string
, ' ');
2438 n_args
= swfdec_bits_get_u16 (&bits
);
2439 g_string_append_c (string
, '(');
2441 /* n_regs = */ swfdec_bits_get_u8 (&bits
);
2442 /* flags = */ swfdec_bits_get_u16 (&bits
);
2445 for (i
= 0; i
< n_args
; i
++) {
2447 const char *arg_name
;
2449 preload
= swfdec_bits_get_u8 (&bits
);
2452 arg_name
= swfdec_bits_get_string (&bits
);
2453 if (preload
== 0 && (arg_name
== NULL
|| *arg_name
== '\0')) {
2454 SWFDEC_ERROR ("empty argument name not allowed");
2455 g_string_free (string
, TRUE
);
2459 g_string_append (string
, ", ");
2460 g_string_append (string
, arg_name
);
2462 g_string_append_printf (string
, " (%u)", preload
);
2464 g_string_append_c (string
, ')');
2465 size
= swfdec_bits_get_u16 (&bits
);
2466 g_string_append_printf (string
, " %u", size
);
2467 return g_string_free (string
, FALSE
);
2471 swfdec_action_print_get_url2 (guint action
, const guint8
*data
, guint len
)
2476 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
2479 method
= data
[0] >> 6;
2481 SWFDEC_ERROR ("GetURL method 3 invalid");
2485 SWFDEC_FIXME ("implement encoding variables using %s", method
== 1 ? "GET" : "POST");
2487 return g_strdup_printf ("GetURL2%s%s%s", method
== 0 ? "" : (method
== 1 ? " GET" : " POST"),
2488 data
[0] & 2 ? " LoadTarget" : "", data
[0] & 1 ? " LoadVariables" : "");
2492 swfdec_action_print_get_url (guint action
, const guint8
*data
, guint len
)
2495 char *url
, *target
, *ret
;
2497 swfdec_bits_init_data (&bits
, data
, len
);
2498 url
= swfdec_bits_get_string (&bits
);
2499 target
= swfdec_bits_get_string (&bits
);
2501 SWFDEC_ERROR ("not enough data in GetURL");
2502 url
= g_strdup ("???");
2504 if (target
== NULL
) {
2505 SWFDEC_ERROR ("not enough data in GetURL");
2506 target
= g_strdup ("???");
2508 if (swfdec_bits_left (&bits
)) {
2509 SWFDEC_WARNING ("leftover bytes in GetURL action");
2511 ret
= g_strdup_printf ("GetURL %s %s", url
, target
);
2518 swfdec_action_print_if (guint action
, const guint8
*data
, guint len
)
2521 SWFDEC_ERROR ("If action length invalid (is %u, should be 2", len
);
2524 return g_strdup_printf ("If %d", GINT16_FROM_LE (*((gint16
*) data
)));
2528 swfdec_action_print_jump (guint action
, const guint8
*data
, guint len
)
2531 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len
);
2534 return g_strdup_printf ("Jump %d", GINT16_FROM_LE (*((gint16
*) data
)));
2538 swfdec_action_print_push (guint action
, const guint8
*data
, guint len
)
2540 gboolean first
= TRUE
;
2542 GString
*string
= g_string_new ("Push");
2544 swfdec_bits_init_data (&bits
, data
, len
);
2545 while (swfdec_bits_left (&bits
)) {
2546 guint type
= swfdec_bits_get_u8 (&bits
);
2548 g_string_append (string
, " ");
2550 g_string_append (string
, ", ");
2553 case 0: /* string */
2555 /* FIXME: need version! */
2556 char *s
= swfdec_bits_get_string (&bits
);
2558 g_string_free (string
, TRUE
);
2561 g_string_append_c (string
, '"');
2562 g_string_append (string
, s
);
2563 g_string_append_c (string
, '"');
2568 g_string_append_printf (string
, "%g", swfdec_bits_get_float (&bits
));
2571 g_string_append (string
, "null");
2573 case 3: /* undefined */
2574 g_string_append (string
, "void");
2576 case 4: /* register */
2577 g_string_append_printf (string
, "Register %u", swfdec_bits_get_u8 (&bits
));
2579 case 5: /* boolean */
2580 g_string_append (string
, swfdec_bits_get_u8 (&bits
) ? "True" : "False");
2582 case 6: /* double */
2583 g_string_append_printf (string
, "%g", swfdec_bits_get_double (&bits
));
2585 case 7: /* 32bit int */
2586 g_string_append_printf (string
, "%d", swfdec_bits_get_u32 (&bits
));
2588 case 8: /* 8bit ConstantPool address */
2589 g_string_append_printf (string
, "Pool %u", swfdec_bits_get_u8 (&bits
));
2591 case 9: /* 16bit ConstantPool address */
2592 g_string_append_printf (string
, "Pool %u", swfdec_bits_get_u16 (&bits
));
2595 SWFDEC_ERROR ("Push: type %u not implemented", type
);
2599 return g_string_free (string
, FALSE
);
2602 /* NB: constant pool actions are special in that they are called at init time */
2604 swfdec_action_print_constant_pool (guint action
, const guint8
*data
, guint len
)
2608 SwfdecConstantPool
*pool
;
2610 /* FIXME: version */
2611 pool
= swfdec_constant_pool_new_from_action (data
, len
, 6);
2613 return g_strdup ("ConstantPool (invalid)");
2614 string
= g_string_new ("ConstantPool");
2615 for (i
= 0; i
< swfdec_constant_pool_size (pool
); i
++) {
2616 g_string_append (string
, i
? ", " : " ");
2617 g_string_append (string
, swfdec_constant_pool_get (pool
, i
));
2618 g_string_append_printf (string
, " (%u)", i
);
2620 return g_string_free (string
, FALSE
);
2625 swfdec_action_print_wait_for_frame2 (guint action
, const guint8
*data
, guint len
)
2628 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
2631 return g_strdup_printf ("WaitForFrame2 %u", (guint
) *data
);
2636 swfdec_action_print_goto_frame2 (guint action
, const guint8
*data
, guint len
)
2638 gboolean play
, bias
;
2641 swfdec_bits_init_data (&bits
, data
, len
);
2642 if (swfdec_bits_getbits (&bits
, 6)) {
2643 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
2645 bias
= swfdec_bits_getbit (&bits
);
2646 play
= swfdec_bits_getbit (&bits
);
2648 return g_strdup_printf ("GotoFrame2 %s +%u", play
? "play" : "stop",
2649 swfdec_bits_get_u16 (&bits
));
2651 return g_strdup_printf ("GotoFrame2 %s", play
? "play" : "stop");
2656 swfdec_action_print_goto_frame (guint action
, const guint8
*data
, guint len
)
2663 frame
= data
[0] | (data
[1] << 8);
2664 return g_strdup_printf ("GotoFrame %u", frame
);
2668 swfdec_action_print_goto_label (guint action
, const guint8
*data
, guint len
)
2670 if (!memchr (data
, 0, len
)) {
2671 SWFDEC_ERROR ("GotoLabel action does not specify a string");
2675 return g_strdup_printf ("GotoLabel %s", data
);
2679 swfdec_action_print_wait_for_frame (guint action
, const guint8
*data
, guint len
)
2686 frame
= data
[0] | (data
[1] << 8);
2688 return g_strdup_printf ("WaitForFrame %u %u", frame
, jump
);
2691 /*** BIG FUNCTION TABLE ***/
2693 const SwfdecActionSpec swfdec_as_actions
[256] = {
2695 [SWFDEC_AS_ACTION_NEXT_FRAME
] = { "NextFrame", NULL
, 0, 0, { swfdec_action_next_frame
, swfdec_action_next_frame
, swfdec_action_next_frame
, swfdec_action_next_frame
, swfdec_action_next_frame
} },
2696 [SWFDEC_AS_ACTION_PREVIOUS_FRAME
] = { "PreviousFrame", NULL
, 0, 0, { swfdec_action_previous_frame
, swfdec_action_previous_frame
, swfdec_action_previous_frame
, swfdec_action_previous_frame
, swfdec_action_previous_frame
} },
2697 [SWFDEC_AS_ACTION_PLAY
] = { "Play", NULL
, 0, 0, { swfdec_action_play
, swfdec_action_play
, swfdec_action_play
, swfdec_action_play
, swfdec_action_play
} },
2698 [SWFDEC_AS_ACTION_STOP
] = { "Stop", NULL
, 0, 0, { swfdec_action_stop
, swfdec_action_stop
, swfdec_action_stop
, swfdec_action_stop
, swfdec_action_stop
} },
2699 [SWFDEC_AS_ACTION_TOGGLE_QUALITY
] = { "ToggleQuality", NULL
},
2700 [SWFDEC_AS_ACTION_STOP_SOUNDS
] = { "StopSounds", NULL
, 0, 0, { swfdec_action_stop_sounds
, swfdec_action_stop_sounds
, swfdec_action_stop_sounds
, swfdec_action_stop_sounds
, swfdec_action_stop_sounds
} },
2702 [SWFDEC_AS_ACTION_ADD
] = { "Add", NULL
, 2, 1, { NULL
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
} },
2703 [SWFDEC_AS_ACTION_SUBTRACT
] = { "Subtract", NULL
, 2, 1, { NULL
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
} },
2704 [SWFDEC_AS_ACTION_MULTIPLY
] = { "Multiply", NULL
, 2, 1, { NULL
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
} },
2705 [SWFDEC_AS_ACTION_DIVIDE
] = { "Divide", NULL
, 2, 1, { NULL
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
, swfdec_action_binary
} },
2706 [SWFDEC_AS_ACTION_EQUALS
] = { "Equals", NULL
, 2, 1, { NULL
, swfdec_action_old_compare
, swfdec_action_old_compare
, swfdec_action_old_compare
, swfdec_action_old_compare
} },
2707 [SWFDEC_AS_ACTION_LESS
] = { "Less", NULL
, 2, 1, { NULL
, swfdec_action_old_compare
, swfdec_action_old_compare
, swfdec_action_old_compare
, swfdec_action_old_compare
} },
2708 [SWFDEC_AS_ACTION_AND
] = { "And", NULL
, 2, 1, { NULL
, /* FIXME */NULL
, swfdec_action_logical
, swfdec_action_logical
, swfdec_action_logical
} },
2709 [SWFDEC_AS_ACTION_OR
] = { "Or", NULL
, 2, 1, { NULL
, /* FIXME */NULL
, swfdec_action_logical
, swfdec_action_logical
, swfdec_action_logical
} },
2710 [SWFDEC_AS_ACTION_NOT
] = { "Not", NULL
, 1, 1, { NULL
, swfdec_action_not_4
, swfdec_action_not_5
, swfdec_action_not_5
, swfdec_action_not_5
} },
2711 [SWFDEC_AS_ACTION_STRING_EQUALS
] = { "StringEquals", NULL
, 2, 1, { NULL
, swfdec_action_string_compare
, swfdec_action_string_compare
, swfdec_action_string_compare
, swfdec_action_string_compare
} },
2712 [SWFDEC_AS_ACTION_STRING_LENGTH
] = { "StringLength", NULL
, 1, 1, { NULL
, swfdec_action_string_length
, swfdec_action_string_length
, swfdec_action_string_length
, swfdec_action_string_length
} },
2713 [SWFDEC_AS_ACTION_STRING_EXTRACT
] = { "StringExtract", NULL
},
2714 [SWFDEC_AS_ACTION_POP
] = { "Pop", NULL
, 1, 0, { NULL
, swfdec_action_pop
, swfdec_action_pop
, swfdec_action_pop
, swfdec_action_pop
} },
2715 [SWFDEC_AS_ACTION_TO_INTEGER
] = { "ToInteger", NULL
, 1, 1, { NULL
, swfdec_action_to_integer
, swfdec_action_to_integer
, swfdec_action_to_integer
, swfdec_action_to_integer
} },
2716 [SWFDEC_AS_ACTION_GET_VARIABLE
] = { "GetVariable", NULL
, 1, 1, { NULL
, swfdec_action_get_variable
, swfdec_action_get_variable
, swfdec_action_get_variable
, swfdec_action_get_variable
} },
2717 [SWFDEC_AS_ACTION_SET_VARIABLE
] = { "SetVariable", NULL
, 2, 0, { NULL
, swfdec_action_set_variable
, swfdec_action_set_variable
, swfdec_action_set_variable
, swfdec_action_set_variable
} },
2718 [SWFDEC_AS_ACTION_SET_TARGET2
] = { "SetTarget2", NULL
, 1, 0, { swfdec_action_set_target2
, swfdec_action_set_target2
, swfdec_action_set_target2
, swfdec_action_set_target2
, swfdec_action_set_target2
} },
2719 [0x21] = { "StringAdd", NULL
, 2, 1, { NULL
, swfdec_action_string_add
, swfdec_action_string_add
, swfdec_action_string_add
, swfdec_action_string_add
} },
2720 [SWFDEC_AS_ACTION_GET_PROPERTY
] = { "GetProperty", NULL
, 2, 1, { NULL
, swfdec_action_get_property
, swfdec_action_get_property
, swfdec_action_get_property
, swfdec_action_get_property
} },
2721 [SWFDEC_AS_ACTION_SET_PROPERTY
] = { "SetProperty", NULL
, 3, 0, { NULL
, swfdec_action_set_property
, swfdec_action_set_property
, swfdec_action_set_property
, swfdec_action_set_property
} },
2722 [SWFDEC_AS_ACTION_CLONE_SPRITE
] = { "CloneSprite", NULL
, 3, 0, { NULL
, swfdec_action_clone_sprite
, swfdec_action_clone_sprite
, swfdec_action_clone_sprite
, swfdec_action_clone_sprite
} },
2723 [SWFDEC_AS_ACTION_REMOVE_SPRITE
] = { "RemoveSprite", NULL
, 1, 0, { NULL
, swfdec_action_remove_sprite
, swfdec_action_remove_sprite
, swfdec_action_remove_sprite
, swfdec_action_remove_sprite
} },
2724 [SWFDEC_AS_ACTION_TRACE
] = { "Trace", NULL
, 1, 0, { NULL
, swfdec_action_trace
, swfdec_action_trace
, swfdec_action_trace
, swfdec_action_trace
} },
2725 [SWFDEC_AS_ACTION_START_DRAG
] = { "StartDrag", NULL
, -1, 0, { NULL
, swfdec_action_start_drag
, swfdec_action_start_drag
, swfdec_action_start_drag
, swfdec_action_start_drag
} },
2726 [SWFDEC_AS_ACTION_END_DRAG
] = { "EndDrag", NULL
, 0, 0, { NULL
, swfdec_action_end_drag
, swfdec_action_end_drag
, swfdec_action_end_drag
, swfdec_action_end_drag
} },
2727 [SWFDEC_AS_ACTION_STRING_LESS
] = { "StringLess", NULL
, 2, 1, { NULL
, swfdec_action_string_compare
, swfdec_action_string_compare
, swfdec_action_string_compare
, swfdec_action_string_compare
} },
2729 [SWFDEC_AS_ACTION_THROW
] = { "Throw", NULL
},
2730 [SWFDEC_AS_ACTION_CAST
] = { "Cast", NULL
},
2731 [SWFDEC_AS_ACTION_IMPLEMENTS
] = { "Implements", NULL
},
2733 [0x30] = { "RandomNumber", NULL
, 1, 1, { NULL
, swfdec_action_random_number
, swfdec_action_random_number
, swfdec_action_random_number
, swfdec_action_random_number
} },
2734 [SWFDEC_AS_ACTION_MB_STRING_LENGTH
] = { "MBStringLength", NULL
},
2735 [SWFDEC_AS_ACTION_CHAR_TO_ASCII
] = { "CharToAscii", NULL
, 1, 1, { NULL
, swfdec_action_char_to_ascii_5
, swfdec_action_char_to_ascii_5
, swfdec_action_char_to_ascii
, swfdec_action_char_to_ascii
} },
2736 [SWFDEC_AS_ACTION_ASCII_TO_CHAR
] = { "AsciiToChar", NULL
, 1, 1, { NULL
, swfdec_action_ascii_to_char_5
, swfdec_action_ascii_to_char_5
, swfdec_action_ascii_to_char
, swfdec_action_ascii_to_char
} },
2737 [SWFDEC_AS_ACTION_GET_TIME
] = { "GetTime", NULL
, 0, 1, { NULL
, swfdec_action_get_time
, swfdec_action_get_time
, swfdec_action_get_time
, swfdec_action_get_time
} },
2738 [SWFDEC_AS_ACTION_MB_STRING_EXTRACT
] = { "MBStringExtract", NULL
},
2739 [SWFDEC_AS_ACTION_MB_CHAR_TO_ASCII
] = { "MBCharToAscii", NULL
},
2740 [SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
] = { "MBAsciiToChar", NULL
, 1, 1, { NULL
, swfdec_action_mb_ascii_to_char_5
, swfdec_action_mb_ascii_to_char_5
, swfdec_action_ascii_to_char
, swfdec_action_ascii_to_char
} },
2742 [SWFDEC_AS_ACTION_DELETE
] = { "Delete", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_delete
, swfdec_action_delete
, swfdec_action_delete
} },
2743 [SWFDEC_AS_ACTION_DELETE2
] = { "Delete2", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_delete2
, swfdec_action_delete2
, swfdec_action_delete2
} },
2744 [SWFDEC_AS_ACTION_DEFINE_LOCAL
] = { "DefineLocal", NULL
, 2, 0, { NULL
, NULL
, swfdec_action_define_local
, swfdec_action_define_local
, swfdec_action_define_local
} },
2745 [SWFDEC_AS_ACTION_CALL_FUNCTION
] = { "CallFunction", NULL
, -1, 1, { NULL
, NULL
, swfdec_action_call_function
, swfdec_action_call_function
, swfdec_action_call_function
} },
2746 [SWFDEC_AS_ACTION_RETURN
] = { "Return", NULL
, 1, 0, { NULL
, NULL
, swfdec_action_return
, swfdec_action_return
, swfdec_action_return
} },
2747 [SWFDEC_AS_ACTION_MODULO
] = { "Modulo", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_modulo
, swfdec_action_modulo
, swfdec_action_modulo
} },
2748 [SWFDEC_AS_ACTION_NEW_OBJECT
] = { "NewObject", NULL
, -1, 1, { NULL
, NULL
, swfdec_action_new_object
, swfdec_action_new_object
, swfdec_action_new_object
} },
2749 [SWFDEC_AS_ACTION_DEFINE_LOCAL2
] = { "DefineLocal2", NULL
, 1, 0, { NULL
, NULL
, swfdec_action_define_local2
, swfdec_action_define_local2
, swfdec_action_define_local2
} },
2750 [SWFDEC_AS_ACTION_INIT_ARRAY
] = { "InitArray", NULL
, -1, 1, { NULL
, NULL
, swfdec_action_init_array
, swfdec_action_init_array
, swfdec_action_init_array
} },
2751 [SWFDEC_AS_ACTION_INIT_OBJECT
] = { "InitObject", NULL
, -1, 1, { NULL
, NULL
, swfdec_action_init_object
, swfdec_action_init_object
, swfdec_action_init_object
} },
2752 [SWFDEC_AS_ACTION_TYPE_OF
] = { "TypeOf", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_type_of
, swfdec_action_type_of
, swfdec_action_type_of
} },
2753 [SWFDEC_AS_ACTION_TARGET_PATH
] = { "TargetPath", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_target_path
, swfdec_action_target_path
, swfdec_action_target_path
} },
2754 [SWFDEC_AS_ACTION_ENUMERATE
] = { "Enumerate", NULL
, 1, -1, { NULL
, NULL
, swfdec_action_enumerate
, swfdec_action_enumerate
, swfdec_action_enumerate
} },
2755 [SWFDEC_AS_ACTION_ADD2
] = { "Add2", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_add2
, swfdec_action_add2
, swfdec_action_add2
} },
2756 [SWFDEC_AS_ACTION_LESS2
] = { "Less2", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_new_comparison
, swfdec_action_new_comparison
, swfdec_action_new_comparison
} },
2757 [SWFDEC_AS_ACTION_EQUALS2
] = { "Equals2", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_equals2_5
, swfdec_action_equals2
, swfdec_action_equals2
} },
2758 [SWFDEC_AS_ACTION_TO_NUMBER
] = { "ToNumber", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_to_number
, swfdec_action_to_number
, swfdec_action_to_number
} },
2759 [SWFDEC_AS_ACTION_TO_STRING
] = { "ToString", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_to_string
, swfdec_action_to_string
, swfdec_action_to_string
} },
2760 [SWFDEC_AS_ACTION_PUSH_DUPLICATE
] = { "PushDuplicate", NULL
, 1, 2, { NULL
, NULL
, swfdec_action_push_duplicate
, swfdec_action_push_duplicate
, swfdec_action_push_duplicate
} },
2761 [SWFDEC_AS_ACTION_SWAP
] = { "Swap", NULL
, 2, 2, { NULL
, NULL
, swfdec_action_swap
, swfdec_action_swap
, swfdec_action_swap
} },
2762 [SWFDEC_AS_ACTION_GET_MEMBER
] = { "GetMember", NULL
, 2, 1, { NULL
, swfdec_action_get_member
, swfdec_action_get_member
, swfdec_action_get_member
, swfdec_action_get_member
} },
2763 [SWFDEC_AS_ACTION_SET_MEMBER
] = { "SetMember", NULL
, 3, 0, { NULL
, swfdec_action_set_member
, swfdec_action_set_member
, swfdec_action_set_member
, swfdec_action_set_member
} },
2764 [SWFDEC_AS_ACTION_INCREMENT
] = { "Increment", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_increment
, swfdec_action_increment
, swfdec_action_increment
} },
2765 [SWFDEC_AS_ACTION_DECREMENT
] = { "Decrement", NULL
, 1, 1, { NULL
, NULL
, swfdec_action_decrement
, swfdec_action_decrement
, swfdec_action_decrement
} },
2766 [SWFDEC_AS_ACTION_CALL_METHOD
] = { "CallMethod", NULL
, -1, 1, { NULL
, NULL
, swfdec_action_call_method
, swfdec_action_call_method
, swfdec_action_call_method
} },
2767 [SWFDEC_AS_ACTION_NEW_METHOD
] = { "NewMethod", NULL
, -1, 1, { NULL
, NULL
, swfdec_action_new_method
, swfdec_action_new_method
, swfdec_action_new_method
} },
2769 [SWFDEC_AS_ACTION_INSTANCE_OF
] = { "InstanceOf", NULL
},
2770 [SWFDEC_AS_ACTION_ENUMERATE2
] = { "Enumerate2", NULL
, 1, -1, { NULL
, NULL
, NULL
, swfdec_action_enumerate2
, swfdec_action_enumerate2
} },
2772 [SWFDEC_AS_ACTION_BIT_AND
] = { "BitAnd", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_bitwise
, swfdec_action_bitwise
, swfdec_action_bitwise
} },
2773 [SWFDEC_AS_ACTION_BIT_OR
] = { "BitOr", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_bitwise
, swfdec_action_bitwise
, swfdec_action_bitwise
} },
2774 [SWFDEC_AS_ACTION_BIT_XOR
] = { "BitXor", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_bitwise
, swfdec_action_bitwise
, swfdec_action_bitwise
} },
2775 [SWFDEC_AS_ACTION_BIT_LSHIFT
] = { "BitLShift", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_shift
, swfdec_action_shift
, swfdec_action_shift
} },
2776 [SWFDEC_AS_ACTION_BIT_RSHIFT
] = { "BitRShift", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_shift
, swfdec_action_shift
, swfdec_action_shift
} },
2777 [SWFDEC_AS_ACTION_BIT_URSHIFT
] = { "BitURShift", NULL
, 2, 1, { NULL
, NULL
, swfdec_action_shift
, swfdec_action_shift
, swfdec_action_shift
} },
2779 [SWFDEC_AS_ACTION_STRICT_EQUALS
] = { "StrictEquals", NULL
, 2, 1, { NULL
, NULL
, NULL
, swfdec_action_strict_equals
, swfdec_action_strict_equals
} },
2780 [SWFDEC_AS_ACTION_GREATER
] = { "Greater", NULL
, 2, 1, { NULL
, NULL
, NULL
, swfdec_action_new_comparison
, swfdec_action_new_comparison
} },
2781 [SWFDEC_AS_ACTION_STRING_GREATER
] = { "StringGreater", NULL
},
2783 [SWFDEC_AS_ACTION_EXTENDS
] = { "Extends", NULL
, 2, 0, { NULL
, NULL
, NULL
, swfdec_action_extends
, swfdec_action_extends
} },
2785 [SWFDEC_AS_ACTION_GOTO_FRAME
] = { "GotoFrame", swfdec_action_print_goto_frame
, 0, 0, { swfdec_action_goto_frame
, swfdec_action_goto_frame
, swfdec_action_goto_frame
, swfdec_action_goto_frame
, swfdec_action_goto_frame
} },
2786 [SWFDEC_AS_ACTION_GET_URL
] = { "GetURL", swfdec_action_print_get_url
, 0, 0, { swfdec_action_get_url
, swfdec_action_get_url
, swfdec_action_get_url
, swfdec_action_get_url
, swfdec_action_get_url
} },
2788 [SWFDEC_AS_ACTION_STORE_REGISTER
] = { "StoreRegister", swfdec_action_print_store_register
, 1, 1, { NULL
, NULL
, swfdec_action_store_register
, swfdec_action_store_register
, swfdec_action_store_register
} },
2789 [SWFDEC_AS_ACTION_CONSTANT_POOL
] = { "ConstantPool", swfdec_action_print_constant_pool
, 0, 0, { NULL
, NULL
, swfdec_action_constant_pool
, swfdec_action_constant_pool
, swfdec_action_constant_pool
} },
2791 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME
] = { "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
} },
2792 [SWFDEC_AS_ACTION_SET_TARGET
] = { "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
} },
2793 [SWFDEC_AS_ACTION_GOTO_LABEL
] = { "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
} },
2796 [0x8d] = { "WaitForFrame2", swfdec_action_print_wait_for_frame2
, 1, 0, { NULL
, swfdec_action_wait_for_frame2
, swfdec_action_wait_for_frame2
, swfdec_action_wait_for_frame2
, swfdec_action_wait_for_frame2
} },
2799 [SWFDEC_AS_ACTION_DEFINE_FUNCTION2
] = { "DefineFunction2", swfdec_action_print_define_function
, 0, -1, { NULL
, NULL
, NULL
, swfdec_action_define_function
, swfdec_action_define_function
} },
2800 [SWFDEC_AS_ACTION_TRY
] = { "Try", NULL
},
2802 [SWFDEC_AS_ACTION_WITH
] = { "With", swfdec_action_print_with
, 1, 0, { NULL
, NULL
, swfdec_action_with
, swfdec_action_with
, swfdec_action_with
} },
2804 [SWFDEC_AS_ACTION_PUSH
] = { "Push", swfdec_action_print_push
, 0, -1, { NULL
, swfdec_action_push
, swfdec_action_push
, swfdec_action_push
, swfdec_action_push
} },
2805 [SWFDEC_AS_ACTION_JUMP
] = { "Jump", swfdec_action_print_jump
, 0, 0, { NULL
, swfdec_action_jump
, swfdec_action_jump
, swfdec_action_jump
, swfdec_action_jump
} },
2806 [SWFDEC_AS_ACTION_GET_URL2
] = { "GetURL2", swfdec_action_print_get_url2
, 2, 0, { NULL
, swfdec_action_get_url2
, swfdec_action_get_url2
, swfdec_action_get_url2
, swfdec_action_get_url2
} },
2808 [SWFDEC_AS_ACTION_DEFINE_FUNCTION
] = { "DefineFunction", swfdec_action_print_define_function
, 0, -1, { NULL
, NULL
, swfdec_action_define_function
, swfdec_action_define_function
, swfdec_action_define_function
} },
2810 [SWFDEC_AS_ACTION_IF
] = { "If", swfdec_action_print_if
, 1, 0, { NULL
, swfdec_action_if
, swfdec_action_if
, swfdec_action_if
, swfdec_action_if
} },
2811 [SWFDEC_AS_ACTION_CALL
] = { "Call", NULL
},
2812 [SWFDEC_AS_ACTION_GOTO_FRAME2
] = { "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
} }