2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
3 * 2007 Pekka Lampila <pekka.lampila@iki.fi>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
24 #include "swfdec_as_interpret.h"
25 #include "swfdec_as_array.h"
26 #include "swfdec_as_context.h"
27 #include "swfdec_as_date.h"
28 #include "swfdec_as_frame_internal.h"
29 #include "swfdec_as_function.h"
30 #include "swfdec_as_internal.h"
31 #include "swfdec_as_script_function.h"
32 #include "swfdec_as_stack.h"
33 #include "swfdec_as_string.h"
34 #include "swfdec_as_strings.h"
35 #include "swfdec_as_super.h"
36 #include "swfdec_as_internal.h"
37 #include "swfdec_debug.h"
42 #include "swfdec_decoder.h"
43 #include "swfdec_load_object.h"
44 #include "swfdec_movie.h"
45 #include "swfdec_player_internal.h"
46 #include "swfdec_sprite.h"
47 #include "swfdec_sprite_movie.h"
48 #include "swfdec_resource.h"
49 #include "swfdec_text_field_movie.h" // for typeof
51 /* Define this to get SWFDEC_WARN'd about missing properties of objects.
52 * This can be useful to find out about unimplemented native properties,
53 * but usually just causes a lot of spam. */
54 //#define SWFDEC_WARN_MISSING_PROPERTIES
56 /*** SUPPORT FUNCTIONS ***/
58 #define swfdec_action_has_register(cx, i) \
59 ((i) < (cx)->frame->n_registers)
61 /*** ALL THE ACTION IS HERE ***/
64 swfdec_action_stop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
66 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
67 SWFDEC_SPRITE_MOVIE (cx
->frame
->target
)->playing
= FALSE
;
69 SWFDEC_ERROR ("no movie to stop");
73 swfdec_action_play (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
75 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
76 SWFDEC_SPRITE_MOVIE (cx
->frame
->target
)->playing
= TRUE
;
78 SWFDEC_ERROR ("no movie to play");
82 swfdec_action_next_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
84 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
85 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
86 if (movie
->frame
< movie
->n_frames
) {
87 swfdec_sprite_movie_goto (movie
, movie
->frame
+ 1);
88 movie
->playing
= FALSE
;
90 SWFDEC_INFO ("can't execute nextFrame, already at last frame");
93 SWFDEC_ERROR ("no movie to nextFrame on");
98 swfdec_action_previous_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
100 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
101 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
102 if (movie
->frame
> 1) {
103 swfdec_sprite_movie_goto (movie
, movie
->frame
- 1);
104 movie
->playing
= FALSE
;
106 SWFDEC_INFO ("can't execute previousFrame, already at first frame");
109 SWFDEC_ERROR ("no movie to previousFrame on");
114 swfdec_action_goto_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
119 SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len
);
122 frame
= data
[0] | (data
[1] << 8);
123 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
124 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
125 swfdec_sprite_movie_goto (movie
, frame
+ 1);
126 movie
->playing
= FALSE
;
128 SWFDEC_ERROR ("no movie to goto on");
133 swfdec_action_goto_label (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
135 if (!memchr (data
, 0, len
)) {
136 SWFDEC_ERROR ("GotoLabel action does not specify a string");
140 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
141 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
143 if (movie
->sprite
== NULL
||
144 (frame
= swfdec_sprite_get_frame (movie
->sprite
, (const char *) data
)) == -1)
146 swfdec_sprite_movie_goto (movie
, frame
+ 1);
147 movie
->playing
= FALSE
;
149 SWFDEC_ERROR ("no movie to goto on");
153 /* returns: frame to go to or 0 on error */
155 swfdec_value_to_frame (SwfdecAsContext
*cx
, SwfdecSpriteMovie
*movie
, SwfdecAsValue
*val
)
159 if (movie
->sprite
== NULL
)
161 if (SWFDEC_AS_VALUE_IS_STRING (val
)) {
162 const char *name
= SWFDEC_AS_VALUE_GET_STRING (val
);
164 if (strchr (name
, ':')) {
165 SWFDEC_ERROR ("FIXME: handle targets");
167 /* treat valid encoded numbers as numbers, otherwise assume it's a frame label */
168 d
= swfdec_as_value_to_number (cx
, val
);
170 frame
= swfdec_sprite_get_frame (movie
->sprite
, name
) + 1;
173 } else if (SWFDEC_AS_VALUE_IS_NUMBER (val
)) {
174 frame
= swfdec_as_value_to_integer (cx
, val
);
176 SWFDEC_WARNING ("cannot convert value to frame number");
177 /* FIXME: how do we treat undefined etc? */
180 return frame
<= 0 ? 0 : frame
;
184 swfdec_action_goto_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
191 swfdec_bits_init_data (&bits
, data
, len
);
192 if (swfdec_bits_getbits (&bits
, 6)) {
193 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
195 bias
= swfdec_bits_getbit (&bits
);
196 play
= swfdec_bits_getbit (&bits
);
198 bias
= swfdec_bits_get_u16 (&bits
);
200 val
= swfdec_as_stack_peek (cx
, 1);
202 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
203 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
204 guint frame
= swfdec_value_to_frame (cx
, movie
, val
);
207 frame
= CLAMP (frame
, 1, movie
->n_frames
);
208 swfdec_sprite_movie_goto (movie
, frame
);
209 movie
->playing
= play
;
212 SWFDEC_ERROR ("no movie to GotoFrame2 on");
214 swfdec_as_stack_pop (cx
);
218 swfdec_script_skip_actions (SwfdecAsContext
*cx
, guint jump
)
220 SwfdecScript
*script
= cx
->frame
->script
;
221 const guint8
*pc
= cx
->frame
->pc
;
222 const guint8
*endpc
= script
->buffer
->data
+ script
->buffer
->length
;
224 /* jump instructions */
231 pc
+= 3 + (pc
[1] | (pc
[2] << 8));
235 } while (jump
-- > 0);
240 swfdec_action_wait_for_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
242 SwfdecSpriteMovie
*movie
;
246 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
249 if (!SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
250 SWFDEC_ERROR ("no movie for WaitForFrame");
254 movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
255 frame
= swfdec_value_to_frame (cx
, movie
, swfdec_as_stack_pop (cx
));
256 loaded
= swfdec_sprite_movie_get_frames_loaded (movie
);
257 if (loaded
< (int) movie
->n_frames
&&
259 swfdec_script_skip_actions (cx
, data
[0]);
263 swfdec_action_wait_for_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
265 SwfdecSpriteMovie
*movie
;
270 SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len
);
273 if (!SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
274 SWFDEC_ERROR ("no movie for WaitForFrame");
278 movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
279 frame
= data
[0] | (data
[1] << 8);
281 loaded
= swfdec_sprite_movie_get_frames_loaded (movie
);
282 if (loaded
< (int) movie
->n_frames
&&
284 swfdec_script_skip_actions (cx
, jump
);
288 swfdec_action_constant_pool (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
290 SwfdecConstantPool
*pool
;
291 SwfdecAsFrame
*frame
;
292 SwfdecBuffer
*buffer
;
295 /* FIXME: lots of hackery to get at the buffer */
296 buffer
= frame
->script
->buffer
;
297 buffer
= swfdec_buffer_new_subbuffer (buffer
, data
- buffer
->data
, len
);
298 pool
= swfdec_constant_pool_new (cx
, buffer
, cx
->version
);
299 swfdec_buffer_unref (buffer
);
302 if (frame
->constant_pool
)
303 swfdec_constant_pool_unref (frame
->constant_pool
);
304 frame
->constant_pool
= pool
;
308 swfdec_action_push (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
312 swfdec_bits_init_data (&bits
, data
, len
);
313 while (swfdec_bits_left (&bits
)) {
314 guint type
= swfdec_bits_get_u8 (&bits
);
315 SWFDEC_LOG ("push type %u", type
);
316 swfdec_as_stack_ensure_free (cx
, 1);
320 char *s
= swfdec_bits_get_string (&bits
, cx
->version
);
322 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
323 SWFDEC_AS_STR_EMPTY
);
325 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
326 swfdec_as_context_give_string (cx
, s
));
331 swfdec_as_value_set_number (cx
, swfdec_as_stack_push (cx
),
332 swfdec_bits_get_float (&bits
));
335 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
337 case 3: /* undefined */
338 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
340 case 4: /* register */
342 guint regnum
= swfdec_bits_get_u8 (&bits
);
343 if (!swfdec_action_has_register (cx
, regnum
)) {
344 SWFDEC_ERROR ("cannot Push register %u: not enough registers", regnum
);
345 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
347 *swfdec_as_stack_push (cx
) = cx
->frame
->registers
[regnum
];
351 case 5: /* boolean */
352 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
353 swfdec_bits_get_u8 (&bits
) ? TRUE
: FALSE
);
356 swfdec_as_value_set_number (cx
, swfdec_as_stack_push (cx
),
357 swfdec_bits_get_double (&bits
));
359 case 7: /* 32bit int */
360 swfdec_as_value_set_integer (cx
, swfdec_as_stack_push (cx
),
361 swfdec_bits_get_s32 (&bits
));
363 case 8: /* 8bit ConstantPool address */
364 case 9: /* 16bit ConstantPool address */
366 guint i
= type
== 8 ? swfdec_bits_get_u8 (&bits
) : swfdec_bits_get_u16 (&bits
);
367 SwfdecConstantPool
*pool
= cx
->frame
->constant_pool
;
369 SWFDEC_ERROR ("no constant pool to push from");
370 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
373 if (i
>= swfdec_constant_pool_size (pool
)) {
374 SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
375 i
, swfdec_constant_pool_size (pool
));
376 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
379 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
380 swfdec_constant_pool_get (pool
, i
));
384 SWFDEC_ERROR ("Push: unknown type %u, skipping", type
);
390 /* NB: name must be GC'd */
391 static SwfdecAsObject
*
392 super_special_movie_lookup_magic (SwfdecAsContext
*cx
, SwfdecAsObject
*o
, const char *name
)
397 o
= swfdec_as_frame_get_variable (cx
->frame
, name
, NULL
);
401 if (SWFDEC_IS_MOVIE (o
)) {
402 SwfdecMovie
*ret
= swfdec_movie_get_by_name (SWFDEC_MOVIE (o
), name
, TRUE
);
404 return SWFDEC_AS_OBJECT (ret
);
406 if (!swfdec_as_object_get_variable (o
, name
, &val
))
408 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
410 return SWFDEC_AS_VALUE_GET_OBJECT (&val
);
413 static SwfdecAsObject
*
414 swfdec_action_get_movie_by_slash_path (SwfdecAsContext
*cx
, const char *path
)
418 o
= cx
->frame
->target
;
419 if (!SWFDEC_IS_MOVIE (o
))
422 o
= SWFDEC_AS_OBJECT (swfdec_movie_get_root (SWFDEC_MOVIE (o
)));
426 char *slash
= strchr (path
, '/');
431 name
= swfdec_as_context_give_string (cx
, g_strndup (path
, slash
- path
));
434 name
= swfdec_as_context_get_string (cx
, path
);
435 path
+= strlen (path
);
437 o
= super_special_movie_lookup_magic (cx
, o
, name
);
438 if (!SWFDEC_IS_MOVIE (o
))
445 swfdec_action_lookup_object (SwfdecAsContext
*cx
, SwfdecAsObject
*o
, const char *path
, const char *end
)
447 gboolean dot_allowed
= TRUE
;
452 o
= cx
->frame
->target
;
453 if (SWFDEC_IS_MOVIE (o
))
459 if (path
[0] == '/') {
461 o
= cx
->frame
->target
;
462 if (!SWFDEC_IS_MOVIE (o
))
464 o
= SWFDEC_AS_OBJECT (swfdec_movie_get_root (SWFDEC_MOVIE (o
)));
469 for (start
= path
; path
< end
; path
++) {
470 if (dot_allowed
&& path
[0] == '.') {
471 if (end
- path
>= 2 && path
[1] == '.') {
475 } else if (path
[0] == ':') {
482 } else if (path
[0] == '/') {
484 } else if (path
- start
< 127) {
492 if (start
[0] == '.' && start
[1] == '.' && start
+ 2 == path
) {
495 for (walk
= cx
->frame
->scope_chain
; walk
; walk
= walk
->next
) {
496 if (SWFDEC_IS_MOVIE (walk
->data
)) {
502 o
= cx
->frame
->target
;
504 /* ".." goes back to parent */
505 if (!SWFDEC_IS_MOVIE (o
))
507 o
= SWFDEC_AS_OBJECT (SWFDEC_MOVIE (o
)->parent
);
511 o
= super_special_movie_lookup_magic (cx
, o
,
512 swfdec_as_context_give_string (cx
, g_strndup (start
, path
- start
)));
516 if (path
- start
< 127)
523 /* FIXME: this function belongs into swfdec_movie.c */
525 swfdec_player_get_movie_from_value (SwfdecPlayer
*player
, SwfdecAsValue
*val
)
530 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
531 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (val
), NULL
);
533 cx
= SWFDEC_AS_CONTEXT (player
);
534 s
= swfdec_as_value_to_string (cx
, val
);
535 return swfdec_player_get_movie_from_string (player
, s
);
539 swfdec_player_get_movie_from_string (SwfdecPlayer
*player
, const char *s
)
543 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
544 g_return_val_if_fail (s
!= NULL
, NULL
);
546 ret
= swfdec_action_lookup_object (SWFDEC_AS_CONTEXT (player
), NULL
, s
, s
+ strlen (s
));
547 if (!SWFDEC_IS_MOVIE (ret
)) {
548 SWFDEC_WARNING ("\"%s\" does not reference a movie", s
);
551 return SWFDEC_MOVIE (ret
);
555 * swfdec_action_get_movie_by_path:
556 * @cx: a #SwfdecAsContext
557 * @path: the path to look up
558 * @object: pointer that takes the object that was looked up. The object may be
560 * @variable: pointer that takes variable part of the path. The variable will
561 * be either %NULL or a non-gc'ed variable name.
563 * Looks up a Flash4-compatible path using "/", ":" and "." style syntax.
565 * Returns: The #SwfdecMovie that was looked up or %NULL if the path does not
566 * specify a valid movie.
569 swfdec_action_get_movie_by_path (SwfdecAsContext
*cx
, const char *path
,
570 SwfdecAsObject
**object
, const char **variable
)
572 SwfdecAsObject
*movie
;
575 g_assert (path
!= NULL
);
576 g_assert (object
!= NULL
);
577 g_assert (variable
!= NULL
);
578 g_assert (cx
->frame
!= NULL
);
580 /* find dot or colon */
581 end
= strpbrk (path
, ".:");
583 /* if no dot or colon, look up slash-path */
585 /* shortcut for the general case */
586 if (strchr (path
, '/') != NULL
) {
587 movie
= swfdec_action_get_movie_by_slash_path (cx
, path
);
599 /* find last dot or colon */
600 while ((s
= strpbrk (end
+ 1, ".:")) != NULL
)
603 /* variable to use is the part after the last dot or colon */
605 /* look up object for start of path */
609 movie
= swfdec_action_lookup_object (cx
, NULL
, path
, end
);
620 swfdec_action_get_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
624 SwfdecAsObject
*object
;
626 val
= swfdec_as_stack_peek (cx
, 1);
627 s
= swfdec_as_value_to_string (cx
, val
);
628 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &s
)) {
631 swfdec_as_object_get_variable (object
, swfdec_as_context_get_string (cx
, s
), val
);
633 SWFDEC_AS_VALUE_SET_OBJECT (val
, object
);
636 swfdec_as_frame_get_variable (cx
->frame
, swfdec_as_context_get_string (cx
, s
), val
);
639 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
640 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
641 SWFDEC_WARNING ("no variable named %s", s
);
647 swfdec_action_set_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
649 const char *s
, *rest
;
650 SwfdecAsObject
*object
;
652 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
653 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &rest
)) {
654 if (object
&& rest
) {
655 swfdec_as_object_set_variable (object
, swfdec_as_context_get_string (cx
, rest
),
656 swfdec_as_stack_peek (cx
, 1));
661 rest
= swfdec_as_context_get_string (cx
, rest
);
662 swfdec_as_frame_set_variable (cx
->frame
, rest
,
663 swfdec_as_stack_peek (cx
, 1), TRUE
, FALSE
);
666 swfdec_as_stack_pop_n (cx
, 2);
670 swfdec_action_get_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
675 id
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
676 if (!SWFDEC_IS_PLAYER (cx
)) {
677 SWFDEC_INFO ("tried using GetProperty in a non-SwfdecPlayer context");
680 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
681 swfdec_as_stack_peek (cx
, 2));
684 SWFDEC_ERROR ("calling GetProperty not on a movieclip object");
685 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
686 } else if (id
> (cx
->version
> 4 ? 21 : 18)) {
687 SWFDEC_WARNING ("trying to GetProperty %u, doesn't exist", id
);
688 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
690 swfdec_movie_property_get (movie
, id
, swfdec_as_stack_peek (cx
, 2));
692 swfdec_as_stack_pop (cx
);
696 swfdec_action_set_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
701 id
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
702 if (!SWFDEC_IS_PLAYER (cx
)) {
703 SWFDEC_INFO ("tried using GetProperty in a non-SwfdecPlayer context");
706 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
707 swfdec_as_stack_peek (cx
, 3));
710 SWFDEC_ERROR ("calling GetProperty not on a movieclip object");
711 } else if (id
> (cx
->version
> 4 ? 21 : 18)) {
712 SWFDEC_WARNING ("trying to SetProperty %u, doesn't exist", id
);
714 swfdec_movie_property_set (movie
, id
, swfdec_as_stack_peek (cx
, 1));
716 swfdec_as_stack_pop_n (cx
, 3);
720 swfdec_action_get_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
722 SwfdecAsObject
*object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 2));
725 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
726 swfdec_as_object_get_variable (object
, name
, swfdec_as_stack_peek (cx
, 2));
727 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
728 if (SWFDEC_AS_VALUE_IS_UNDEFINED (swfdec_as_stack_peek (cx
, 2))) {
729 SWFDEC_WARNING ("no variable named %s:%s", G_OBJECT_TYPE_NAME (object
), name
);
733 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
735 swfdec_as_stack_pop (cx
);
739 swfdec_action_set_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
741 if (SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 3))) {
742 const char *name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
743 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 3)),
744 name
, swfdec_as_stack_peek (cx
, 1));
746 swfdec_as_stack_pop_n (cx
, 3);
750 swfdec_action_trace (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
755 val
= swfdec_as_stack_peek (cx
, 1);
756 if (val
->type
== SWFDEC_AS_TYPE_UNDEFINED
) {
757 s
= SWFDEC_AS_STR_undefined
;
759 s
= swfdec_as_value_to_string (cx
, val
);
761 swfdec_as_stack_pop (cx
);
762 g_signal_emit_by_name (cx
, "trace", s
);
765 /* stack looks like this: [ function, this, arg1, arg2, ... ] */
766 /* stack must be at least 2 elements big */
768 swfdec_action_call (SwfdecAsContext
*cx
, guint n_args
, SwfdecAsObject
*super
)
770 SwfdecAsFunction
*fun
;
771 SwfdecAsObject
*thisp
;
773 if (!SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 1)))
775 fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 1));
776 if (!SWFDEC_IS_AS_FUNCTION (fun
))
778 if (!SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 2))) {
781 thisp
= SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 2));
783 swfdec_as_stack_pop_n (cx
, 2);
784 /* sanitize argument count */
785 if (n_args
>= swfdec_as_stack_get_size (cx
))
786 n_args
= swfdec_as_stack_get_size (cx
);
787 if (super
== NULL
&& SWFDEC_IS_AS_SUPER (fun
)) {
788 SWFDEC_LOG ("replacing super object on frame");
789 super
= swfdec_as_super_resolve_property (SWFDEC_AS_SUPER (fun
), NULL
);
791 swfdec_as_function_call_full (fun
, thisp
, FALSE
, super
, n_args
, NULL
, NULL
);
796 if (n_args
> swfdec_as_stack_get_size (cx
))
797 n_args
= swfdec_as_stack_get_size (cx
);
798 swfdec_as_stack_pop_n (cx
, n_args
);
799 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
804 swfdec_action_call_function (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
806 SwfdecAsFrame
*frame
= cx
->frame
;
810 SwfdecAsValue
*fun
, *thisp
;
812 swfdec_as_stack_ensure_size (cx
, 2);
813 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
814 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
815 thisp
= swfdec_as_stack_peek (cx
, 2);
816 fun
= swfdec_as_stack_peek (cx
, 1);
817 obj
= swfdec_as_frame_get_variable (frame
, name
, fun
);
819 SWFDEC_AS_VALUE_SET_OBJECT (thisp
, obj
);
821 SWFDEC_AS_VALUE_SET_NULL (thisp
);
822 SWFDEC_AS_VALUE_SET_UNDEFINED (fun
);
824 if (!swfdec_action_call (cx
, n_args
, NULL
)) {
825 SWFDEC_WARNING ("no function named %s", name
);
830 swfdec_action_call_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
833 SwfdecAsObject
*obj
, *super
;
834 SwfdecAsObject
*pobj
= NULL
;
838 swfdec_as_stack_ensure_size (cx
, 3);
839 obj
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 2));
840 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
841 val
= swfdec_as_stack_peek (cx
, 1);
843 name
= swfdec_as_value_to_string (cx
, val
);
844 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val
) ||
845 name
== SWFDEC_AS_STR_EMPTY
) {
846 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 3));
847 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 2), obj
);
851 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 3), obj
);
852 swfdec_as_object_get_variable_and_flags (obj
, name
, swfdec_as_stack_peek (cx
, 2), NULL
, &pobj
);
855 if (SWFDEC_AS_VALUE_IS_STRING (val
))
856 name
= SWFDEC_AS_VALUE_GET_STRING (val
);
859 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_peek (cx
, 3));
860 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
862 swfdec_as_stack_pop (cx
);
863 /* setup super to point to the right prototype */
864 if (SWFDEC_IS_AS_SUPER (obj
)) {
865 super
= swfdec_as_super_resolve_property (SWFDEC_AS_SUPER (obj
), name
);
866 } else if (cx
->version
> 6 && pobj
!= obj
) {
869 super
= obj
->prototype
;
873 if (!swfdec_action_call (cx
, n_args
, super
)) {
874 SWFDEC_WARNING ("no function named \"%s\" on object %s", name
,
875 obj
? G_OBJECT_TYPE_NAME(obj
) : "unknown");
880 swfdec_action_pop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
882 swfdec_as_stack_pop (cx
);
886 swfdec_action_binary (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
890 r
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
891 l
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
893 case SWFDEC_AS_ACTION_ADD
:
896 case SWFDEC_AS_ACTION_SUBTRACT
:
899 case SWFDEC_AS_ACTION_MULTIPLY
:
902 case SWFDEC_AS_ACTION_DIVIDE
:
903 if (cx
->version
< 5) {
905 swfdec_as_stack_pop (cx
);
906 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR__ERROR_
);
922 g_assert_not_reached ();
925 swfdec_as_stack_pop (cx
);
926 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), l
);
930 swfdec_action_add2_to_primitive (SwfdecAsValue
*value
)
932 SwfdecAsObject
*object
;
935 if (!SWFDEC_AS_VALUE_IS_OBJECT (value
))
937 object
= SWFDEC_AS_VALUE_GET_OBJECT (value
);
938 if (SWFDEC_IS_MOVIE (object
))
941 if (SWFDEC_IS_AS_DATE (object
) && swfdec_gc_object_get_context (object
)->version
> 5)
942 name
= SWFDEC_AS_STR_toString
;
944 name
= SWFDEC_AS_STR_valueOf
;
945 swfdec_as_object_call (SWFDEC_AS_VALUE_GET_OBJECT (value
), name
, 0, NULL
, value
);
949 swfdec_action_add2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
951 SwfdecAsValue
*rval
, *lval
, rtmp
, ltmp
;
953 rval
= swfdec_as_stack_peek (cx
, 1);
954 lval
= swfdec_as_stack_peek (cx
, 2);
957 swfdec_action_add2_to_primitive (&rtmp
);
958 if (!SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
) || SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
)))
960 swfdec_action_add2_to_primitive (<mp
);
961 if (!SWFDEC_AS_VALUE_IS_OBJECT (<mp
) || SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (<mp
)))
964 if (SWFDEC_AS_VALUE_IS_STRING (lval
) || SWFDEC_AS_VALUE_IS_STRING (rval
)) {
965 const char *lstr
, *rstr
;
966 lstr
= swfdec_as_value_to_string (cx
, lval
);
967 rstr
= swfdec_as_value_to_string (cx
, rval
);
968 lstr
= swfdec_as_str_concat (cx
, lstr
, rstr
);
969 swfdec_as_stack_pop (cx
);
970 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), lstr
);
973 d
= swfdec_as_value_to_number (cx
, lval
);
974 d2
= swfdec_as_value_to_number (cx
, rval
);
976 swfdec_as_stack_pop (cx
);
977 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), d
);
982 swfdec_action_new_comparison (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
984 SwfdecAsValue
*lval
, *rval
;
987 rval
= swfdec_as_stack_peek (cx
, 1);
988 lval
= swfdec_as_stack_peek (cx
, 2);
990 /* swap if we do a greater comparison */
991 if (action
== SWFDEC_AS_ACTION_GREATER
) {
992 SwfdecAsValue
*tmp
= lval
;
996 /* comparison with object is always false */
997 swfdec_as_value_to_primitive (lval
);
998 if (SWFDEC_AS_VALUE_IS_OBJECT (lval
) &&
999 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (lval
))) {
1000 swfdec_as_stack_pop (cx
);
1001 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
1004 /* same for the rval */
1005 swfdec_as_value_to_primitive (rval
);
1006 if (SWFDEC_AS_VALUE_IS_OBJECT (rval
) &&
1007 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (rval
))) {
1008 swfdec_as_stack_pop (cx
);
1009 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
1012 /* movieclips are not objects, but they evaluate to NaN, so we can handle them here */
1013 if (SWFDEC_AS_VALUE_IS_OBJECT (rval
) ||
1014 SWFDEC_AS_VALUE_IS_OBJECT (lval
)) {
1015 swfdec_as_stack_pop (cx
);
1016 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1019 /* if both are strings, compare strings */
1020 if (SWFDEC_AS_VALUE_IS_STRING (rval
) &&
1021 SWFDEC_AS_VALUE_IS_STRING (lval
)) {
1022 const char *ls
= SWFDEC_AS_VALUE_GET_STRING (lval
);
1023 const char *rs
= SWFDEC_AS_VALUE_GET_STRING (rval
);
1025 if (ls
== SWFDEC_AS_STR_EMPTY
) {
1026 cmp
= rs
== SWFDEC_AS_STR_EMPTY
? 0 : 1;
1027 } else if (rs
== SWFDEC_AS_STR_EMPTY
) {
1030 cmp
= strcmp (ls
, rs
);
1032 swfdec_as_stack_pop (cx
);
1033 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cmp
< 0);
1036 /* convert to numbers and compare those */
1037 l
= swfdec_as_value_to_number (cx
, lval
);
1038 r
= swfdec_as_value_to_number (cx
, rval
);
1039 swfdec_as_stack_pop (cx
);
1040 /* NaN results in undefined */
1041 if (isnan (l
) || isnan (r
)) {
1042 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1045 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), l
< r
);
1049 swfdec_action_not (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1051 if (cx
->version
<= 4) {
1052 double d
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1053 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), d
== 0 ? 1 : 0);
1055 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1),
1056 !swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1)));
1061 swfdec_action_jump (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1066 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2)", len
);
1069 offset
= data
[0] | (data
[1] << 8);
1070 cx
->frame
->pc
+= 5 + (int) offset
;
1074 swfdec_action_if (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1077 SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len
);
1080 if (swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1))) {
1081 gint16 offset
= data
[0] | (data
[1] << 8);
1082 cx
->frame
->pc
+= 5 + (int) offset
;
1084 swfdec_as_stack_pop (cx
);
1088 swfdec_action_decrement (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1092 val
= swfdec_as_stack_peek (cx
, 1);
1093 swfdec_as_value_set_number (cx
, val
, swfdec_as_value_to_number (cx
, val
) - 1);
1097 swfdec_action_increment (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1101 val
= swfdec_as_stack_peek (cx
, 1);
1102 swfdec_as_value_set_number (cx
, val
, swfdec_as_value_to_number (cx
, val
) + 1);
1106 swfdec_action_get_url (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1111 swfdec_bits_init_data (&bits
, data
, len
);
1112 url
= swfdec_bits_get_string (&bits
, cx
->version
);
1113 target
= swfdec_bits_get_string (&bits
, cx
->version
);
1114 if (url
== NULL
|| target
== NULL
) {
1115 SWFDEC_ERROR ("not enough data in GetURL");
1120 if (swfdec_bits_left (&bits
)) {
1121 SWFDEC_WARNING ("leftover bytes in GetURL action");
1123 if (!SWFDEC_IS_PLAYER (cx
)) {
1124 SWFDEC_ERROR ("GetURL without a SwfdecPlayer");
1126 swfdec_resource_load (SWFDEC_PLAYER (cx
), target
, url
, NULL
);
1133 swfdec_as_interpret_load_variables_on_finish (SwfdecAsObject
*target
,
1137 swfdec_as_object_decode (target
, text
);
1139 // only call onData for sprite movies
1140 // FIXME: is it called even when loading fails?
1141 swfdec_actor_queue_script (SWFDEC_ACTOR (target
), SWFDEC_EVENT_DATA
);
1145 swfdec_as_interpret_encode_variables_foreach (SwfdecAsObject
*object
,
1146 const char *variable
, SwfdecAsValue
*value
, guint flags
, gpointer data
)
1148 SwfdecAsContext
*context
;
1149 GString
*variables
= data
;
1152 context
= swfdec_gc_object_get_context (object
);
1153 // FIXME: check propflags?
1155 if (variables
->len
> 0)
1156 g_string_append_c (variables
, '&');
1158 escaped
= swfdec_as_string_escape (context
, variable
);
1159 g_string_append (variables
, escaped
);
1162 g_string_append_c (variables
, '=');
1164 escaped
= swfdec_as_string_escape (context
,
1165 swfdec_as_value_to_string (context
, value
));
1166 g_string_append (variables
, escaped
);
1173 swfdec_as_interpret_encode_variables (SwfdecAsObject
*object
)
1175 GString
*variables
= g_string_new ("");
1177 SWFDEC_FIXME ("Encoding variables for getURL2 shouldn't include child movies");
1178 swfdec_as_object_foreach (object
,
1179 swfdec_as_interpret_encode_variables_foreach
, variables
);
1181 return g_string_free (variables
, FALSE
);
1185 swfdec_action_get_url2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1187 const char *target
, *url
;
1188 guint method
, internal
, variables
;
1189 SwfdecBuffer
*buffer
;
1192 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
1196 method
= data
[0] & 3;
1198 SWFDEC_ERROR ("GetURL method 3 invalid");
1201 internal
= data
[0] & 64;
1202 variables
= data
[0] & 128;
1204 url
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1207 if (method
== 1 || method
== 2) {
1208 char *text
= swfdec_as_interpret_encode_variables (cx
->frame
->target
);
1210 url
= swfdec_as_context_give_string (cx
, g_strjoin (NULL
, url
,
1211 strchr (url
, '?') == NULL
? "?" : "&", text
, NULL
));
1213 // don't send the nul-byte
1214 buffer
= swfdec_buffer_new_for_data (g_memdup (text
, strlen (text
)),
1220 if (!SWFDEC_IS_PLAYER (cx
)) {
1221 SWFDEC_ERROR ("GetURL2 action requires a SwfdecPlayer");
1222 } else if (variables
) {
1225 target
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1226 movie
= swfdec_player_get_movie_from_string (SWFDEC_PLAYER (cx
), target
);
1227 if (movie
!= NULL
) {
1228 swfdec_load_object_create (SWFDEC_AS_OBJECT (movie
), url
, buffer
, 0,
1229 NULL
, NULL
, NULL
, swfdec_as_interpret_load_variables_on_finish
);
1231 } else if (internal
) {
1232 swfdec_resource_load_movie (SWFDEC_PLAYER (cx
), swfdec_as_stack_peek (cx
, 1),
1235 target
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1236 swfdec_resource_load (SWFDEC_PLAYER (cx
), target
, url
, buffer
);
1239 swfdec_as_stack_pop_n (cx
, 2);
1243 swfdec_action_string_add (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1245 const char *lval
, *rval
;
1247 rval
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1248 lval
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1249 lval
= swfdec_as_str_concat (cx
, lval
, rval
);
1250 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 2), lval
);
1251 swfdec_as_stack_pop (cx
);
1255 swfdec_action_push_duplicate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1257 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
1259 *swfdec_as_stack_push (cx
) = *val
;
1263 swfdec_action_random_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1268 val
= swfdec_as_stack_peek (cx
, 1);
1269 max
= swfdec_as_value_to_integer (cx
, val
);
1272 swfdec_as_value_set_number (cx
, val
, 0);
1274 swfdec_as_value_set_number (cx
, val
, g_rand_int_range (cx
->rand
, 0, max
));
1278 swfdec_action_old_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1283 l
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
1284 r
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1286 case SWFDEC_AS_ACTION_EQUALS
:
1289 case SWFDEC_AS_ACTION_LESS
:
1293 g_assert_not_reached ();
1296 swfdec_as_stack_pop (cx
);
1297 if (cx
->version
< 5) {
1298 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), cond
? 1 : 0);
1300 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1305 swfdec_action_string_extract (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1310 n
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1311 start
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1312 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 3));
1313 swfdec_as_stack_pop_n (cx
, 2);
1314 left
= g_utf8_strlen (s
, -1);
1316 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR_EMPTY
);
1318 } else if (start
< 2) {
1324 if (n
< 0 || n
> left
)
1327 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
1328 swfdec_as_str_sub (cx
, s
, start
, n
));
1332 swfdec_action_string_length (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1337 v
= swfdec_as_stack_peek (cx
, 1);
1338 s
= swfdec_as_value_to_string (cx
, v
);
1339 swfdec_as_value_set_integer (cx
, v
, g_utf8_strlen (s
, -1));
1343 swfdec_action_string_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1348 r
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1349 l
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1351 case SWFDEC_AS_ACTION_STRING_EQUALS
:
1354 case SWFDEC_AS_ACTION_STRING_LESS
:
1355 cond
= strcmp (l
, r
) < 0;
1357 case SWFDEC_AS_ACTION_STRING_GREATER
:
1358 cond
= strcmp (l
, r
) > 0;
1362 g_assert_not_reached ();
1365 swfdec_as_stack_pop (cx
);
1366 if (cx
->version
< 5) {
1367 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), cond
? 1 : 0);
1369 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1374 swfdec_action_equals2_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1376 SwfdecAsValue
*rval
, *lval
;
1377 SwfdecAsValue rtmp
, ltmp
;
1378 SwfdecAsValueType ltype
, rtype
;
1382 rval
= swfdec_as_stack_peek (cx
, 1);
1383 lval
= swfdec_as_stack_peek (cx
, 2);
1386 swfdec_as_value_to_primitive (&rtmp
);
1387 swfdec_as_value_to_primitive (<mp
);
1391 /* get objects compared */
1392 if (ltype
== SWFDEC_AS_TYPE_OBJECT
&& rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1393 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (<mp
);
1394 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
);
1396 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1397 lo
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (lo
)));
1398 ro
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (ro
)));
1399 } else if (SWFDEC_IS_MOVIE (lo
)) {
1400 swfdec_as_value_to_primitive (rval
);
1402 if (rtype
!= SWFDEC_AS_TYPE_OBJECT
) {
1406 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1407 } else if (SWFDEC_IS_MOVIE (ro
)) {
1408 swfdec_as_value_to_primitive (lval
);
1410 if (ltype
!= SWFDEC_AS_TYPE_OBJECT
) {
1414 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1416 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1417 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1423 /* compare strings */
1424 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1425 /* FIXME: flash 5 case insensitive? */
1426 cond
= SWFDEC_AS_VALUE_GET_STRING (<mp
) == SWFDEC_AS_VALUE_GET_STRING (&rtmp
);
1430 /* convert to numbers */
1431 if (SWFDEC_AS_VALUE_IS_OBJECT (<mp
) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (<mp
))) {
1432 l
= swfdec_as_value_to_number (cx
, lval
);
1434 l
= swfdec_as_value_to_number (cx
, <mp
);
1436 if (SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
))) {
1437 r
= swfdec_as_value_to_number (cx
, rval
);
1439 r
= swfdec_as_value_to_number (cx
, &rtmp
);
1442 /* get rid of undefined and null */
1443 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1444 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1451 /* else compare as numbers */
1452 if (isnan (l
) && isnan (r
))
1453 cond
= ltype
== rtype
;
1458 swfdec_as_stack_pop (cx
);
1459 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1463 swfdec_action_equals2_6 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1465 SwfdecAsValue
*rval
, *lval
;
1466 SwfdecAsValueType ltype
, rtype
;
1470 rval
= swfdec_as_stack_peek (cx
, 1);
1471 lval
= swfdec_as_stack_peek (cx
, 2);
1475 /* get objects compared */
1476 if (ltype
== SWFDEC_AS_TYPE_OBJECT
&& rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1477 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1478 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1480 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1481 lo
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (lo
)));
1482 ro
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (ro
)));
1483 } else if (SWFDEC_IS_MOVIE (lo
)) {
1484 swfdec_as_value_to_primitive (rval
);
1486 if (rtype
!= SWFDEC_AS_TYPE_OBJECT
) {
1490 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1491 } else if (SWFDEC_IS_MOVIE (ro
)) {
1492 swfdec_as_value_to_primitive (lval
);
1494 if (ltype
!= SWFDEC_AS_TYPE_OBJECT
) {
1498 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1504 /* if one of the values is an object, call valueOf.
1505 * If it's still an object, return FALSE */
1506 swfdec_as_value_to_primitive (lval
);
1508 if (ltype
== SWFDEC_AS_TYPE_OBJECT
) {
1512 swfdec_as_value_to_primitive (rval
);
1514 if (rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1518 /* now we have a comparison without objects */
1520 /* get rid of undefined and null */
1521 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1522 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1529 /* compare strings */
1530 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1531 /* FIXME: flash 5 case insensitive? */
1532 cond
= SWFDEC_AS_VALUE_GET_STRING (lval
) == SWFDEC_AS_VALUE_GET_STRING (rval
);
1536 /* else compare as numbers */
1537 l
= swfdec_as_value_to_number (cx
, lval
);
1538 r
= swfdec_as_value_to_number (cx
, rval
);
1540 if (isnan (l
) && isnan (r
))
1541 cond
= ltype
== rtype
;
1546 swfdec_as_stack_pop (cx
);
1547 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1551 swfdec_action_equals2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1553 if (cx
->version
<= 5) {
1554 swfdec_action_equals2_5 (cx
, action
, data
, len
);
1556 swfdec_action_equals2_6 (cx
, action
, data
, len
);
1561 swfdec_action_strict_equals (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1563 SwfdecAsValue
*rval
, *lval
;
1566 rval
= swfdec_as_stack_peek (cx
, 1);
1567 lval
= swfdec_as_stack_peek (cx
, 2);
1569 if (rval
->type
!= lval
->type
) {
1572 switch (rval
->type
) {
1573 case SWFDEC_AS_TYPE_UNDEFINED
:
1574 case SWFDEC_AS_TYPE_NULL
:
1577 case SWFDEC_AS_TYPE_BOOLEAN
:
1578 cond
= SWFDEC_AS_VALUE_GET_BOOLEAN (rval
) == SWFDEC_AS_VALUE_GET_BOOLEAN (lval
);
1580 case SWFDEC_AS_TYPE_NUMBER
:
1583 r
= SWFDEC_AS_VALUE_GET_NUMBER (rval
);
1584 l
= SWFDEC_AS_VALUE_GET_NUMBER (lval
);
1585 cond
= (l
== r
) || (isnan (l
) && isnan (r
));
1588 case SWFDEC_AS_TYPE_STRING
:
1589 cond
= SWFDEC_AS_VALUE_GET_STRING (rval
) == SWFDEC_AS_VALUE_GET_STRING (lval
);
1591 case SWFDEC_AS_TYPE_OBJECT
:
1593 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1594 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1595 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1596 cond
= swfdec_movie_resolve (SWFDEC_MOVIE (lo
)) == swfdec_movie_resolve (SWFDEC_MOVIE (ro
));
1597 } else if (!SWFDEC_IS_MOVIE (lo
) && !SWFDEC_IS_MOVIE (ro
)) {
1604 case SWFDEC_AS_TYPE_INT
:
1606 g_assert_not_reached ();
1611 swfdec_as_stack_pop (cx
);
1612 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1616 swfdec_action_do_set_target (SwfdecAsContext
*cx
, const char *target
, const char *end
)
1618 swfdec_as_frame_set_target (cx
->frame
, NULL
);
1620 if (target
!= end
) {
1621 SwfdecAsObject
*o
= swfdec_action_lookup_object (cx
, NULL
, target
, end
);
1623 SWFDEC_WARNING ("target \"%s\" is not an object", target
);
1624 } else if (!SWFDEC_IS_MOVIE (o
)) {
1625 SWFDEC_FIXME ("target \"%s\" is not a movie, something weird is supposed to happen now", target
);
1628 swfdec_as_frame_set_target (cx
->frame
, o
);
1633 swfdec_action_set_target (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1637 end
= memchr (data
, 0, len
);
1639 SWFDEC_ERROR ("SetTarget action does not specify a string");
1642 swfdec_action_do_set_target (cx
, (const char *) data
, end
);
1646 swfdec_action_set_target2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1650 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1651 swfdec_action_do_set_target (cx
, s
, s
+ strlen (s
));
1652 swfdec_as_stack_pop (cx
);
1656 swfdec_action_start_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1658 SwfdecRect rect
, *rectp
= NULL
;
1661 guint stack_size
= 3;
1663 swfdec_as_stack_ensure_size (cx
, 3);
1664 center
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
1665 if (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 3))) {
1666 swfdec_as_stack_ensure_size (cx
, 7);
1667 rect
.x0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 7));
1668 rect
.y0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 6));
1669 rect
.x1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 5));
1670 rect
.y1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 4));
1671 swfdec_rect_scale (&rect
, &rect
, SWFDEC_TWIPS_SCALE_FACTOR
);
1675 if (!SWFDEC_IS_PLAYER (cx
)) {
1676 SWFDEC_ERROR ("called startDrag on a non-SwfdecPlayer");
1678 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
), swfdec_as_stack_peek (cx
, 1));
1679 if (SWFDEC_IS_ACTOR (movie
)) {
1680 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), SWFDEC_ACTOR (movie
), center
, rectp
);
1682 SWFDEC_ERROR ("startDrag on something not an Actor");
1685 swfdec_as_stack_pop_n (cx
, stack_size
);
1689 swfdec_action_end_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1691 if (SWFDEC_IS_PLAYER (cx
)) {
1692 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), NULL
, FALSE
, NULL
);
1694 SWFDEC_WARNING ("can't end a drag on non-players");
1699 swfdec_action_stop_sounds (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1701 if (SWFDEC_IS_PLAYER (cx
)) {
1702 swfdec_player_stop_all_sounds (SWFDEC_PLAYER (cx
));
1707 swfdec_action_new_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1709 SwfdecAsValue
*constructor
;
1710 SwfdecAsFunction
*fun
;
1713 swfdec_as_stack_ensure_size (cx
, 2);
1714 swfdec_action_get_variable (cx
, action
, data
, len
);
1715 constructor
= swfdec_as_stack_peek (cx
, 1);
1716 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1717 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 2, n_args
);
1718 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1719 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
))) {
1720 SWFDEC_WARNING ("not a constructor");
1724 swfdec_as_stack_pop_n (cx
, 2);
1725 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1729 swfdec_as_stack_pop_n (cx
, n_args
+ 1);
1730 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1734 swfdec_action_new_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1736 SwfdecAsValue
*constructor
;
1737 SwfdecAsFunction
*fun
;
1741 swfdec_as_stack_ensure_size (cx
, 3);
1742 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1744 constructor
= swfdec_as_stack_peek (cx
, 2);
1745 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
1746 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 3, n_args
);
1747 if (name
== SWFDEC_AS_STR_EMPTY
||
1748 SWFDEC_AS_VALUE_IS_UNDEFINED (swfdec_as_stack_peek (cx
, 1))) {
1750 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
)) {
1751 SWFDEC_WARNING ("NewMethod called without an object to get variable %s from", name
);
1754 swfdec_as_object_get_variable (SWFDEC_AS_VALUE_GET_OBJECT (constructor
),
1757 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1758 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
))) {
1759 SWFDEC_WARNING ("%s is not a constructor", name
);
1763 swfdec_as_stack_pop_n (cx
, 3);
1764 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1768 swfdec_as_stack_pop_n (cx
, n_args
+ 2);
1769 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1773 swfdec_action_init_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1775 SwfdecAsObject
*object
;
1776 guint i
, n_args
, size
;
1778 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1779 swfdec_as_stack_pop (cx
);
1780 if (n_args
* 2 > swfdec_as_stack_get_size (cx
)) {
1781 size
= swfdec_as_stack_get_size (cx
);
1782 SWFDEC_FIXME ("InitObject action with too small stack, help!");
1789 object
= swfdec_as_object_new (cx
);
1790 for (i
= 0; i
< n_args
; i
++) {
1791 const char *s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1792 swfdec_as_object_set_variable (object
, s
, swfdec_as_stack_peek (cx
, 1));
1793 swfdec_as_stack_pop_n (cx
, 2);
1795 swfdec_as_stack_pop_n (cx
, size
);
1796 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
1800 swfdec_action_init_array (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1803 SwfdecAsObject
*array
;
1805 swfdec_as_stack_ensure_size (cx
, 1);
1806 n
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1807 swfdec_as_stack_pop (cx
);
1808 array
= swfdec_as_array_new (cx
);
1809 /* NB: we can't increase the stack here, as the number can easily be MAXINT */
1810 for (i
= 0; i
< n
&& swfdec_as_stack_get_size (cx
) > 0; i
++) {
1811 swfdec_as_stack_ensure_size (cx
, 1);
1812 swfdec_as_array_push (SWFDEC_AS_ARRAY (array
), swfdec_as_stack_pop (cx
));
1816 swfdec_as_value_set_integer (cx
, &val
, n
);
1817 swfdec_as_object_set_variable (array
, SWFDEC_AS_STR_length
, &val
);
1819 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), array
);
1823 swfdec_action_define_function (SwfdecAsContext
*cx
, guint action
,
1824 const guint8
*data
, guint len
)
1826 char *function_name
;
1827 const char *name
= NULL
;
1828 guint i
, n_args
, size
, n_registers
;
1830 SwfdecBuffer
*buffer
;
1831 SwfdecAsFunction
*fun
;
1832 SwfdecAsFrame
*frame
;
1833 SwfdecScript
*script
;
1835 SwfdecScriptArgument
*args
;
1836 gboolean v2
= (action
== 0x8e);
1839 swfdec_bits_init_data (&bits
, data
, len
);
1840 function_name
= swfdec_bits_get_string (&bits
, cx
->version
);
1841 if (function_name
== NULL
) {
1842 SWFDEC_ERROR ("could not parse function name");
1845 n_args
= swfdec_bits_get_u16 (&bits
);
1847 n_registers
= swfdec_bits_get_u8 (&bits
);
1848 if (n_registers
== 0)
1850 flags
= swfdec_bits_get_u16 (&bits
);
1855 args
= g_new0 (SwfdecScriptArgument
, n_args
);
1856 for (i
= 0; i
< n_args
&& swfdec_bits_left (&bits
); i
++) {
1858 args
[i
].preload
= swfdec_bits_get_u8 (&bits
);
1859 if (args
[i
].preload
&& args
[i
].preload
>= n_registers
) {
1860 SWFDEC_ERROR ("argument %u cannot be preloaded into register %u out of %u",
1861 i
, args
[i
].preload
, n_registers
);
1862 /* FIXME: figure out correct error handling here */
1863 args
[i
].preload
= 0;
1866 args
[i
].name
= swfdec_bits_get_string (&bits
, cx
->version
);
1867 if (args
[i
].name
== NULL
|| args
[i
].name
== '\0') {
1868 SWFDEC_ERROR ("empty argument name not allowed");
1872 /* FIXME: check duplicate arguments */
1877 size
= swfdec_bits_get_u16 (&bits
);
1878 /* check the script can be created */
1879 if (frame
->script
->buffer
->data
+ frame
->script
->buffer
->length
< frame
->pc
+ 3 + len
+ size
) {
1880 SWFDEC_ERROR ("size of function is too big");
1882 g_free (function_name
);
1885 /* create the script */
1886 buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
1887 frame
->pc
+ 3 + len
- frame
->script
->buffer
->data
, size
);
1888 swfdec_bits_init (&bits
, buffer
);
1889 if (*function_name
) {
1890 name
= function_name
;
1891 } else if (swfdec_as_stack_get_size (cx
) > 0) {
1892 /* This is kind of a hack that uses a feature of the Adobe compiler:
1893 * foo = function () {} is compiled as these actions:
1894 * Push "foo", DefineFunction, SetVariable/SetMember
1895 * With this knowledge we can inspect the topmost stack member, since
1896 * it will contain the name this function will soon be assigned to.
1898 if (SWFDEC_AS_VALUE_IS_STRING (swfdec_as_stack_peek (cx
, 1)))
1899 name
= SWFDEC_AS_VALUE_GET_STRING (swfdec_as_stack_peek (cx
, 1));
1902 name
= "unnamed_function";
1903 script
= swfdec_script_new_from_bits (&bits
, name
, cx
->version
);
1904 swfdec_buffer_unref (buffer
);
1905 if (script
== NULL
) {
1906 SWFDEC_ERROR ("failed to create script");
1908 g_free (function_name
);
1911 if (frame
->constant_pool
)
1912 script
->constant_pool
= swfdec_buffer_ref (swfdec_constant_pool_get_buffer (frame
->constant_pool
));
1913 script
->flags
= flags
;
1914 script
->n_registers
= n_registers
;
1915 script
->n_arguments
= n_args
;
1916 script
->arguments
= args
;
1917 /* see function-scope tests */
1918 if (cx
->version
> 5) {
1919 /* FIXME: or original target? */
1920 fun
= swfdec_as_script_function_new (frame
->original_target
, frame
->scope_chain
, script
);
1922 fun
= swfdec_as_script_function_new (frame
->original_target
, NULL
, script
);
1926 /* This is a hack that should only trigger for functions defined in the init scripts.
1927 * It is supposed to ensure that those functions inherit their target when being
1928 * called instead of when being defined */
1929 if (!SWFDEC_IS_MOVIE (frame
->original_target
))
1930 SWFDEC_AS_SCRIPT_FUNCTION (fun
)->target
= NULL
;
1931 /* attach the function */
1932 if (*function_name
== '\0') {
1933 swfdec_as_stack_ensure_free (cx
, 1);
1934 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), SWFDEC_AS_OBJECT (fun
));
1936 SwfdecAsValue funval
;
1937 /* FIXME: really varobj? Not eval or sth like that? */
1938 name
= swfdec_as_context_get_string (cx
, function_name
);
1939 SWFDEC_AS_VALUE_SET_OBJECT (&funval
, SWFDEC_AS_OBJECT (fun
));
1940 swfdec_as_object_set_variable (frame
->target
, name
, &funval
);
1943 /* update current context */
1944 frame
->pc
+= 3 + len
+ size
;
1945 g_free (function_name
);
1949 swfdec_action_bitwise (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1953 a
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1954 b
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1967 g_assert_not_reached ();
1971 swfdec_as_stack_pop (cx
);
1972 swfdec_as_value_set_integer (cx
, swfdec_as_stack_peek (cx
, 1), a
);
1976 swfdec_action_shift (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1980 amount
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1982 value
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1986 value
= value
<< amount
;
1989 value
= ((gint
) value
) >> amount
;
1992 value
= ((guint
) value
) >> amount
;
1995 g_assert_not_reached ();
1998 swfdec_as_stack_pop (cx
);
1999 swfdec_as_value_set_integer (cx
, swfdec_as_stack_peek (cx
, 1), value
);
2003 swfdec_action_to_integer (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2005 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2007 swfdec_as_value_set_integer (cx
, val
, swfdec_as_value_to_integer (cx
, val
));
2011 swfdec_action_target_path (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2017 val
= swfdec_as_stack_peek (cx
, 1);
2019 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
) ||
2020 !SWFDEC_IS_MOVIE (movie
= (SwfdecMovie
*) SWFDEC_AS_VALUE_GET_OBJECT (val
))) {
2021 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2024 s
= swfdec_movie_get_path (movie
, TRUE
);
2025 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_give_string (cx
, s
));
2029 swfdec_action_define_local (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2033 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
2034 swfdec_as_frame_set_variable (cx
->frame
, name
, swfdec_as_stack_peek (cx
, 1),
2036 swfdec_as_stack_pop_n (cx
, 2);
2040 swfdec_action_define_local2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2042 SwfdecAsValue val
= { 0, };
2045 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
2046 swfdec_as_frame_set_variable (cx
->frame
, name
, &val
, FALSE
, TRUE
);
2047 swfdec_as_stack_pop (cx
);
2051 swfdec_action_end (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2053 swfdec_as_frame_return (cx
->frame
, NULL
);
2057 swfdec_action_return (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2059 swfdec_as_frame_return (cx
->frame
, swfdec_as_stack_pop (cx
));
2063 swfdec_action_delete (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2067 gboolean success
= FALSE
;
2069 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
2070 val
= swfdec_as_stack_peek (cx
, 2);
2071 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2072 success
= swfdec_as_object_delete_variable (
2073 SWFDEC_AS_VALUE_GET_OBJECT (val
), name
) == SWFDEC_AS_DELETE_DELETED
;
2075 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
2076 swfdec_as_stack_pop_n (cx
, 1);
2080 swfdec_action_delete2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2084 gboolean success
= FALSE
;
2086 val
= swfdec_as_stack_peek (cx
, 1);
2087 name
= swfdec_as_value_to_string (cx
, val
);
2088 success
= swfdec_as_frame_delete_variable (cx
->frame
, name
) == SWFDEC_AS_DELETE_DELETED
;
2089 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
2093 swfdec_action_store_register (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2096 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
2099 if (!swfdec_action_has_register (cx
, *data
)) {
2100 SWFDEC_ERROR ("Cannot store into register %u, not enough registers", (guint
) *data
);
2103 cx
->frame
->registers
[*data
] = *swfdec_as_stack_peek (cx
, 1);
2107 swfdec_action_modulo (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2111 y
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
2112 x
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
2113 /* yay, we're portable! */
2120 SWFDEC_FIXME ("errno set after fmod");
2123 swfdec_as_stack_pop (cx
);
2124 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), x
);
2128 swfdec_action_swap (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2130 swfdec_as_stack_swap (cx
, 1, 2);
2134 swfdec_action_to_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2136 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1),
2137 swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)));
2141 swfdec_action_to_string (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2143 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
2144 swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1)));
2148 swfdec_action_type_of (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2153 val
= swfdec_as_stack_peek (cx
, 1);
2154 switch (val
->type
) {
2155 case SWFDEC_AS_TYPE_NUMBER
:
2156 type
= SWFDEC_AS_STR_number
;
2158 case SWFDEC_AS_TYPE_BOOLEAN
:
2159 type
= SWFDEC_AS_STR_boolean
;
2161 case SWFDEC_AS_TYPE_STRING
:
2162 type
= SWFDEC_AS_STR_string
;
2164 case SWFDEC_AS_TYPE_UNDEFINED
:
2165 type
= SWFDEC_AS_STR_undefined
;
2167 case SWFDEC_AS_TYPE_NULL
:
2168 type
= SWFDEC_AS_STR_null
;
2170 case SWFDEC_AS_TYPE_OBJECT
:
2172 SwfdecAsObject
*obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2173 if (SWFDEC_IS_MOVIE (obj
)) {
2174 SwfdecMovie
*movie
= swfdec_movie_resolve (SWFDEC_MOVIE (obj
));
2175 if (movie
!= NULL
&& SWFDEC_IS_TEXT_FIELD_MOVIE (movie
) &&
2176 movie
->state
== SWFDEC_MOVIE_STATE_RUNNING
) {
2177 type
= SWFDEC_AS_STR_object
;
2179 type
= SWFDEC_AS_STR_movieclip
;
2181 } else if (SWFDEC_IS_AS_FUNCTION (obj
)) {
2182 type
= SWFDEC_AS_STR_function
;
2184 type
= SWFDEC_AS_STR_object
;
2188 case SWFDEC_AS_TYPE_INT
:
2190 g_assert_not_reached ();
2191 type
= SWFDEC_AS_STR_EMPTY
;
2194 SWFDEC_AS_VALUE_SET_STRING (val
, type
);
2198 swfdec_action_get_time (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2203 swfdec_as_context_get_time (cx
, &tv
);
2204 /* we assume here that swfdec_as_context_get_time always returns a tv > start_time */
2205 diff
= tv
.tv_sec
- cx
->start_time
.tv_sec
;
2207 diff
+= (tv
.tv_usec
- cx
->start_time
.tv_usec
) / 1000;
2209 swfdec_as_value_set_number (cx
, swfdec_as_stack_push (cx
), diff
);
2213 swfdec_action_is_instance_of (SwfdecAsObject
*object
,
2214 SwfdecAsObject
*constructor
)
2217 SwfdecAsObject
*class, *prototype
;
2220 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
2221 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (constructor
), FALSE
);
2223 // FIXME: propflag tests are wrong, and we shouldn't get __proto__.prototype
2224 swfdec_as_object_get_variable (constructor
, SWFDEC_AS_STR_prototype
, &val
);
2225 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
2227 prototype
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
2230 while ((class = swfdec_as_object_get_prototype (class)) != NULL
) {
2231 if (class == prototype
)
2233 for (iter
= class->interfaces
; iter
!= NULL
; iter
= iter
->next
) {
2234 if (iter
->data
== prototype
)
2243 swfdec_action_instance_of (SwfdecAsContext
*cx
, guint action
,
2244 const guint8
*data
, guint len
)
2247 SwfdecAsObject
*object
, *constructor
;
2249 val
= swfdec_as_stack_pop (cx
);
2250 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2251 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2256 val
= swfdec_as_stack_pop (cx
);
2257 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2258 object
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2264 if (object
== NULL
|| constructor
== NULL
) {
2265 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
), FALSE
);
2269 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
2270 swfdec_action_is_instance_of (object
, constructor
));
2274 swfdec_action_cast (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2278 SwfdecAsObject
*object
, *constructor
;
2280 val
= swfdec_as_stack_pop (cx
);
2281 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2282 object
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2287 val
= swfdec_as_stack_pop (cx
);
2288 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2289 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2294 if (object
== NULL
|| constructor
== NULL
) {
2295 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2299 if (swfdec_action_is_instance_of (object
, constructor
)) {
2300 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
2302 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2307 swfdec_action_implements (SwfdecAsContext
*cx
, guint action
,
2308 const guint8
*data
, guint len
)
2310 SwfdecAsValue
*val
, *argv
;
2311 SwfdecAsObject
*object
, *proto
, *interface
;
2314 swfdec_as_stack_ensure_size (cx
, 2);
2316 val
= swfdec_as_stack_pop (cx
);
2317 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2318 object
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2319 swfdec_as_object_get_variable (object
, SWFDEC_AS_STR_prototype
, val
);
2320 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2321 proto
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2330 val
= swfdec_as_stack_pop (cx
);
2331 argc
= swfdec_as_value_to_integer (cx
, val
);
2334 swfdec_as_stack_ensure_size (cx
, argc
);
2335 argv
= swfdec_as_stack_pop_n (cx
, argc
);
2343 for (i
= 0; i
< argc
; i
++) {
2344 if (!SWFDEC_AS_VALUE_IS_OBJECT (&argv
[i
]))
2346 interface
= SWFDEC_AS_VALUE_GET_OBJECT (&argv
[i
]);
2347 swfdec_as_object_get_variable (interface
, SWFDEC_AS_STR_prototype
, val
);
2348 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
))
2351 g_slist_prepend (proto
->interfaces
, SWFDEC_AS_VALUE_GET_OBJECT (val
));
2356 swfdec_action_extends (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2358 SwfdecAsValue
*superclass
, *subclass
, proto
;
2359 SwfdecAsObject
*prototype
;
2360 SwfdecAsObject
*super
;
2362 superclass
= swfdec_as_stack_peek (cx
, 1);
2363 subclass
= swfdec_as_stack_peek (cx
, 2);
2364 if (!SWFDEC_AS_VALUE_IS_OBJECT (superclass
) ||
2365 !SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (superclass
))) {
2366 SWFDEC_ERROR ("superclass is not a function");
2369 if (!SWFDEC_AS_VALUE_IS_OBJECT (subclass
)) {
2370 SWFDEC_ERROR ("subclass is not an object");
2373 super
= SWFDEC_AS_VALUE_GET_OBJECT (superclass
);
2374 prototype
= swfdec_as_object_new_empty (cx
);
2375 swfdec_as_object_get_variable (super
, SWFDEC_AS_STR_prototype
, &proto
);
2376 swfdec_as_object_set_variable_and_flags (prototype
, SWFDEC_AS_STR___proto__
, &proto
,
2377 SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
2378 swfdec_as_object_set_variable_and_flags (prototype
, SWFDEC_AS_STR___constructor__
,
2379 superclass
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_VERSION_6_UP
);
2380 SWFDEC_AS_VALUE_SET_OBJECT (&proto
, prototype
);
2381 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_OBJECT (subclass
),
2382 SWFDEC_AS_STR_prototype
, &proto
);
2384 swfdec_as_stack_pop_n (cx
, 2);
2388 swfdec_action_enumerate_foreach (SwfdecAsObject
*object
, const char *variable
,
2389 SwfdecAsValue
*value
, guint flags
, gpointer listp
)
2391 GSList
**list
= listp
;
2393 if (flags
& SWFDEC_AS_VARIABLE_HIDDEN
)
2396 *list
= g_slist_remove (*list
, variable
);
2397 *list
= g_slist_prepend (*list
, (gpointer
) variable
);
2402 swfdec_action_do_enumerate (SwfdecAsContext
*cx
, SwfdecAsObject
*object
)
2405 GSList
*walk
, *list
= NULL
;
2407 for (i
= 0; i
< 256 && object
; i
++) {
2408 swfdec_as_object_foreach (object
, swfdec_action_enumerate_foreach
, &list
);
2409 object
= swfdec_as_object_get_prototype (object
);
2412 swfdec_as_context_abort (swfdec_gc_object_get_context (object
),
2413 "Prototype recursion limit exceeded");
2414 g_slist_free (list
);
2417 list
= g_slist_reverse (list
);
2419 for (walk
= list
; walk
; walk
= walk
->next
) {
2420 /* 8 is an arbitrary value */
2422 swfdec_as_stack_ensure_free (cx
, 8);
2426 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
), walk
->data
);
2428 g_slist_free (list
);
2432 swfdec_action_enumerate2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2435 SwfdecAsObject
*obj
;
2437 val
= swfdec_as_stack_peek (cx
, 1);
2438 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2439 SWFDEC_WARNING ("Enumerate called without an object");
2440 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2443 obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2444 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2445 swfdec_action_do_enumerate (cx
, obj
);
2449 swfdec_action_enumerate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2451 /* FIXME: make this proper functions */
2452 swfdec_action_get_variable (cx
, action
, data
, len
);
2453 swfdec_action_enumerate2 (cx
, action
, data
, len
);
2457 swfdec_action_logical (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2461 if (cx
->version
<= 4) {
2462 l
= (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)) != 0);
2463 // don't call second parameter if not necessary
2464 if ((action
== SWFDEC_AS_ACTION_AND
&& !l
) ||
2465 (action
!= SWFDEC_AS_ACTION_AND
&& l
)) {
2466 r
= (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2)) != 0);
2471 l
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1));
2472 r
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
2475 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 2),
2476 (action
== SWFDEC_AS_ACTION_AND
) ? (l
&& r
) : (l
|| r
));
2477 swfdec_as_stack_pop (cx
);
2481 swfdec_action_char_to_ascii (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2483 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2484 const char *s
= swfdec_as_value_to_string (cx
, val
);
2486 if (cx
->version
<= 5) {
2487 char *ascii
= g_convert (s
, -1, "LATIN1", "UTF-8", NULL
, NULL
, NULL
);
2489 if (ascii
== NULL
) {
2490 /* This can happen if a Flash 5 movie gets loaded into a Flash 7 movie */
2491 SWFDEC_FIXME ("Someone threw unconvertible text %s at Flash <= 5", s
);
2492 swfdec_as_value_set_integer (cx
, val
, 0); /* FIXME: what to return??? */
2494 swfdec_as_value_set_integer (cx
, val
, (guchar
) ascii
[0]);
2498 gunichar
*uni
= g_utf8_to_ucs4_fast (s
, -1, NULL
);
2501 /* This should never happen, everything is valid UTF-8 in here */
2502 g_warning ("conversion of character %s failed", s
);
2503 swfdec_as_value_set_integer (cx
, val
, 0);
2505 swfdec_as_value_set_integer (cx
, val
, uni
[0]);
2512 swfdec_action_ascii_to_char (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2514 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2516 if (cx
->version
<= 5) {
2521 if (action
== SWFDEC_AS_ACTION_ASCII_TO_CHAR
) {
2522 s
[0] = ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 256;
2525 g_assert (action
== SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
);
2527 i
= ((guint
) swfdec_as_value_to_integer (cx
, val
));
2538 utf8
= g_convert (s
, -1, "UTF-8", "LATIN1", NULL
, NULL
, NULL
);
2540 g_warning ("conversion of character %u failed", (guint
) s
[0]);
2541 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2543 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, utf8
));
2548 gunichar c
= ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 65536;
2550 s
= g_ucs4_to_utf8 (&c
, 1, NULL
, NULL
, NULL
);
2552 g_warning ("conversion of character %u failed", (guint
) c
);
2553 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2555 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, s
));
2562 swfdec_action_throw (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2565 swfdec_as_context_throw (cx
, swfdec_as_stack_pop (cx
));
2569 const guint8
* catch_start
;
2570 const guint8
* finally_start
;
2574 gboolean use_register
;
2576 guint register_number
;
2577 char * variable_name
;
2580 SwfdecAsObject
* scope_object
;
2584 swfdec_action_try_data_free (gpointer data
)
2586 TryData
*try_data
= data
;
2588 g_return_if_fail (try_data
!= NULL
);
2590 if (!try_data
->use_register
)
2591 g_free (try_data
->variable_name
);
2596 swfdec_action_try_end_finally (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2598 SwfdecAsValue
*exception_value
= data
;
2600 g_return_if_fail (SWFDEC_IS_AS_VALUE (exception_value
));
2602 // finally has ended and we had exception stored, throw it
2603 if (!cx
->exception
&& cx
->frame
== frame
)
2604 swfdec_as_context_throw (cx
, exception_value
);
2610 swfdec_action_try_end_catch (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2612 TryData
*try_data
= data
;
2613 SwfdecAsValue
*exception_value
, val
;
2615 g_return_if_fail (try_data
!= NULL
);
2617 if (try_data
->scope_object
) {
2618 g_assert (frame
->scope_chain
->data
== try_data
->scope_object
);
2619 frame
->scope_chain
=
2620 g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2621 try_data
->scope_object
= NULL
;
2624 if (try_data
->finally_start
&& swfdec_as_context_catch (cx
, &val
))
2626 // we got an exception while in catch block:
2627 // create new block for finally to pass on the exception
2628 // jump to that block
2630 exception_value
= g_malloc (sizeof (SwfdecAsValue
));
2631 *exception_value
= val
;
2633 // FIXME: the exception value is not marked while finally block runs
2634 swfdec_as_frame_push_block (frame
, try_data
->finally_start
,
2635 try_data
->finally_start
+ try_data
->finally_size
,
2636 swfdec_action_try_end_finally
, exception_value
);
2637 frame
->pc
= try_data
->finally_start
;
2640 swfdec_action_try_data_free (try_data
);
2644 swfdec_action_try_end_try (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2646 TryData
*try_data
= data
;
2649 g_return_if_fail (try_data
!= NULL
);
2651 // if we don't have a catch block, we handle try block exactly like it was
2653 if (!try_data
->catch_start
) {
2654 swfdec_action_try_end_catch (cx
, frame
, try_data
);
2658 if (swfdec_as_context_catch (cx
, &val
))
2660 // we got an exception while in try block:
2661 // set the exception variable
2662 // add new block for catch and jump to it
2663 try_data
->scope_object
= swfdec_as_object_new_empty (cx
);
2664 frame
->scope_chain
= g_slist_prepend (frame
->scope_chain
,
2665 try_data
->scope_object
);
2667 swfdec_as_frame_push_block (frame
, try_data
->catch_start
,
2668 try_data
->catch_start
+ try_data
->catch_size
,
2669 swfdec_action_try_end_catch
, try_data
);
2670 frame
->pc
= try_data
->catch_start
;
2672 if (try_data
->use_register
)
2674 if (try_data
->register_number
< frame
->n_registers
) {
2675 frame
->registers
[try_data
->register_number
] = val
;
2677 SWFDEC_ERROR ("cannot set Error to register %u: not enough registers",
2678 try_data
->register_number
);
2683 swfdec_as_object_set_variable (try_data
->scope_object
,
2684 swfdec_as_context_get_string (cx
, try_data
->variable_name
), &val
);
2689 swfdec_action_try_data_free (try_data
);
2694 swfdec_action_try (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2699 gboolean use_finally
, use_catch
;
2702 SWFDEC_ERROR ("With action requires a length of at least 8, but got %u",
2707 try_data
= g_malloc0 (sizeof (TryData
));
2709 swfdec_bits_init_data (&bits
, data
, len
);
2711 swfdec_bits_getbits (&bits
, 5); // reserved
2712 try_data
->use_register
= swfdec_bits_getbit (&bits
);
2713 use_finally
= swfdec_bits_getbit (&bits
);
2714 use_catch
= swfdec_bits_getbit (&bits
);
2716 try_size
= swfdec_bits_get_u16 (&bits
);
2717 try_data
->catch_size
= swfdec_bits_get_u16 (&bits
);
2718 try_data
->finally_size
= swfdec_bits_get_u16 (&bits
);
2720 try_data
->catch_start
= data
+ len
+ try_size
;
2722 try_data
->finally_start
= data
+ len
+ try_size
+
2723 (use_catch
? try_data
->catch_size
: 0);
2726 if (try_data
->use_register
) {
2727 try_data
->register_number
= swfdec_bits_get_u8 (&bits
);
2729 try_data
->variable_name
=
2730 swfdec_bits_get_string (&bits
, cx
->version
);
2733 if (swfdec_bits_left (&bits
)) {
2734 SWFDEC_WARNING ("leftover bytes in Try action");
2737 if (try_data
->catch_start
|| try_data
->finally_start
) {
2738 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ try_size
,
2739 swfdec_action_try_end_try
, try_data
);
2741 SWFDEC_WARNING ("Try with neither catch nor finally block");
2742 swfdec_action_try_data_free (try_data
);
2747 swfdec_action_pop_with (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer with_object
)
2749 g_assert (frame
->scope_chain
->data
== with_object
);
2750 frame
->scope_chain
= g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2754 swfdec_action_with (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2756 SwfdecAsObject
*object
;
2760 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2761 swfdec_as_stack_pop (cx
);
2764 offset
= data
[0] | (data
[1] << 8);
2765 object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 1));
2766 if (object
== NULL
) {
2767 SWFDEC_INFO ("With called without an object, skipping");
2768 cx
->frame
->pc
= (guint8
*) data
+ len
+ offset
;
2770 cx
->frame
->scope_chain
= g_slist_prepend (cx
->frame
->scope_chain
, object
);
2771 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ offset
,
2772 swfdec_action_pop_with
, object
);
2774 swfdec_as_stack_pop (cx
);
2778 swfdec_action_remove_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2780 if (!SWFDEC_IS_MOVIE (cx
->frame
->target
)) {
2781 SWFDEC_FIXME ("target is not a movie in RemoveSprite");
2782 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2783 SWFDEC_INFO ("tried using RemoveSprite in a non-SwfdecPlayer context");
2785 SwfdecMovie
*movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2786 swfdec_as_stack_peek (cx
, 1));
2787 if (movie
&& swfdec_depth_classify (movie
->depth
) == SWFDEC_DEPTH_CLASS_DYNAMIC
) {
2788 SWFDEC_LOG ("removing clip %s", movie
->name
);
2789 swfdec_movie_remove (movie
);
2791 SWFDEC_INFO ("cannot remove movie");
2794 swfdec_as_stack_pop (cx
);
2798 swfdec_action_clone_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2800 SwfdecMovie
*movie
, *new_movie
;
2801 const char *new_name
;
2804 depth
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1)) - 16384;
2805 new_name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
2806 if (!SWFDEC_IS_MOVIE (cx
->frame
->target
)) {
2807 SWFDEC_FIXME ("target is not a movie in CloneSprite");
2808 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2809 SWFDEC_INFO ("tried using CloneSprite in a non-SwfdecPlayer context");
2811 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2812 swfdec_as_stack_peek (cx
, 3));
2813 if (movie
== NULL
) {
2814 SWFDEC_ERROR ("Object is not an SwfdecMovie object");
2815 swfdec_as_stack_pop_n (cx
, 3);
2818 new_movie
= swfdec_movie_duplicate (movie
, new_name
, depth
);
2820 SWFDEC_LOG ("duplicated %s as %s to depth %u", movie
->name
, new_movie
->name
, new_movie
->depth
);
2823 swfdec_as_stack_pop_n (cx
, 3);
2826 /*** PRINT FUNCTIONS ***/
2829 swfdec_action_print_with (guint action
, const guint8
*data
, guint len
)
2832 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2835 return g_strdup_printf ("With %u", data
[0] | (data
[1] << 8));
2839 swfdec_action_print_store_register (guint action
, const guint8
*data
, guint len
)
2842 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
2845 return g_strdup_printf ("StoreRegister %u", (guint
) *data
);
2849 swfdec_action_print_set_target (guint action
, const guint8
*data
, guint len
)
2851 if (!memchr (data
, 0, len
)) {
2852 SWFDEC_ERROR ("SetTarget action does not specify a string");
2855 return g_strconcat ("SetTarget ", data
, NULL
);
2859 swfdec_action_print_define_function (guint action
, const guint8
*data
, guint len
)
2863 const char *function_name
;
2864 guint i
, n_args
, size
;
2865 gboolean v2
= (action
== 0x8e);
2867 string
= g_string_new (v2
? "DefineFunction2 " : "DefineFunction ");
2868 swfdec_bits_init_data (&bits
, data
, len
);
2869 /* FIXME: version! */
2870 function_name
= swfdec_bits_get_string (&bits
, 7);
2871 if (function_name
== NULL
) {
2872 SWFDEC_ERROR ("could not parse function name");
2873 g_string_free (string
, TRUE
);
2876 if (*function_name
) {
2877 g_string_append (string
, function_name
);
2878 g_string_append_c (string
, ' ');
2880 n_args
= swfdec_bits_get_u16 (&bits
);
2881 g_string_append_c (string
, '(');
2883 /* n_regs = */ swfdec_bits_get_u8 (&bits
);
2884 /* flags = */ swfdec_bits_get_u16 (&bits
);
2887 for (i
= 0; i
< n_args
; i
++) {
2889 const char *arg_name
;
2891 preload
= swfdec_bits_get_u8 (&bits
);
2894 arg_name
= swfdec_bits_get_string (&bits
, 7);
2895 if (preload
== 0 && (arg_name
== NULL
|| *arg_name
== '\0')) {
2896 SWFDEC_ERROR ("empty argument name not allowed");
2897 g_string_free (string
, TRUE
);
2901 g_string_append (string
, ", ");
2902 g_string_append (string
, arg_name
);
2904 g_string_append_printf (string
, " (%u)", preload
);
2906 g_string_append_c (string
, ')');
2907 size
= swfdec_bits_get_u16 (&bits
);
2908 g_string_append_printf (string
, " %u", size
);
2909 return g_string_free (string
, FALSE
);
2913 swfdec_action_print_get_url2 (guint action
, const guint8
*data
, guint len
)
2918 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
2921 method
= data
[0] >> 6;
2923 SWFDEC_ERROR ("GetURL method 3 invalid");
2927 SWFDEC_FIXME ("implement encoding variables using %s", method
== 1 ? "GET" : "POST");
2929 return g_strdup_printf ("GetURL2%s%s%s", method
== 0 ? "" : (method
== 1 ? " GET" : " POST"),
2930 data
[0] & 2 ? " LoadTarget" : "", data
[0] & 1 ? " LoadVariables" : "");
2934 swfdec_action_print_get_url (guint action
, const guint8
*data
, guint len
)
2937 char *url
, *target
, *ret
;
2939 swfdec_bits_init_data (&bits
, data
, len
);
2940 url
= swfdec_bits_get_string (&bits
, 7);
2941 target
= swfdec_bits_get_string (&bits
, 7);
2943 SWFDEC_ERROR ("not enough data in GetURL");
2944 url
= g_strdup ("???");
2946 if (target
== NULL
) {
2947 SWFDEC_ERROR ("not enough data in GetURL");
2948 target
= g_strdup ("???");
2950 if (swfdec_bits_left (&bits
)) {
2951 SWFDEC_WARNING ("leftover bytes in GetURL action");
2953 ret
= g_strdup_printf ("GetURL %s %s", url
, target
);
2960 swfdec_action_print_if (guint action
, const guint8
*data
, guint len
)
2965 SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len
);
2968 offset
= data
[0] | (data
[1] << 8);
2969 return g_strdup_printf ("If %d", (int) offset
);
2973 swfdec_action_print_jump (guint action
, const guint8
*data
, guint len
)
2978 SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len
);
2981 offset
= data
[0] | (data
[1] << 8);
2982 return g_strdup_printf ("Jump %d", (int) offset
);
2986 swfdec_action_print_push (guint action
, const guint8
*data
, guint len
)
2988 gboolean first
= TRUE
;
2990 GString
*string
= g_string_new ("Push");
2992 swfdec_bits_init_data (&bits
, data
, len
);
2993 while (swfdec_bits_left (&bits
)) {
2994 guint type
= swfdec_bits_get_u8 (&bits
);
2996 g_string_append (string
, " ");
2998 g_string_append (string
, ", ");
3001 case 0: /* string */
3003 /* FIXME: need version! */
3004 char *s
= swfdec_bits_get_string (&bits
, 7);
3006 g_string_free (string
, TRUE
);
3009 g_string_append_c (string
, '"');
3010 g_string_append (string
, s
);
3011 g_string_append_c (string
, '"');
3016 g_string_append_printf (string
, "%g", swfdec_bits_get_float (&bits
));
3019 g_string_append (string
, "null");
3021 case 3: /* undefined */
3022 g_string_append (string
, "void");
3024 case 4: /* register */
3025 g_string_append_printf (string
, "Register %u", swfdec_bits_get_u8 (&bits
));
3027 case 5: /* boolean */
3028 g_string_append (string
, swfdec_bits_get_u8 (&bits
) ? "True" : "False");
3030 case 6: /* double */
3031 g_string_append_printf (string
, "%g", swfdec_bits_get_double (&bits
));
3033 case 7: /* 32bit int */
3034 g_string_append_printf (string
, "%d", swfdec_bits_get_s32 (&bits
));
3036 case 8: /* 8bit ConstantPool address */
3037 g_string_append_printf (string
, "Pool %u", swfdec_bits_get_u8 (&bits
));
3039 case 9: /* 16bit ConstantPool address */
3040 g_string_append_printf (string
, "Pool %u", swfdec_bits_get_u16 (&bits
));
3043 SWFDEC_ERROR ("Push: unknown type %u, skipping", type
);
3047 return g_string_free (string
, FALSE
);
3050 /* NB: constant pool actions are special in that they are called at init time */
3052 swfdec_action_print_constant_pool (guint action
, const guint8
*data
, guint len
)
3056 SwfdecConstantPool
*pool
;
3057 SwfdecBuffer
*buffer
;
3059 /* FIXME: version */
3060 buffer
= swfdec_buffer_new_static (data
, len
);
3061 pool
= swfdec_constant_pool_new (NULL
, buffer
, 6);
3063 return g_strdup ("ConstantPool (invalid)");
3064 string
= g_string_new ("ConstantPool");
3065 for (i
= 0; i
< swfdec_constant_pool_size (pool
); i
++) {
3066 g_string_append (string
, i
? ", " : " ");
3067 g_string_append (string
, swfdec_constant_pool_get (pool
, i
));
3068 g_string_append_printf (string
, " (%u)", i
);
3070 swfdec_constant_pool_unref (pool
);
3071 swfdec_buffer_unref (buffer
);
3072 return g_string_free (string
, FALSE
);
3076 swfdec_action_print_wait_for_frame2 (guint action
, const guint8
*data
, guint len
)
3079 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
3082 return g_strdup_printf ("WaitForFrame2 %u", (guint
) *data
);
3086 swfdec_action_print_goto_frame2 (guint action
, const guint8
*data
, guint len
)
3088 gboolean play
, bias
;
3091 swfdec_bits_init_data (&bits
, data
, len
);
3092 if (swfdec_bits_getbits (&bits
, 6)) {
3093 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
3095 bias
= swfdec_bits_getbit (&bits
);
3096 play
= swfdec_bits_getbit (&bits
);
3098 return g_strdup_printf ("GotoFrame2 %s +%u", play
? "play" : "stop",
3099 swfdec_bits_get_u16 (&bits
));
3101 return g_strdup_printf ("GotoFrame2 %s", play
? "play" : "stop");
3106 swfdec_action_print_goto_frame (guint action
, const guint8
*data
, guint len
)
3113 frame
= data
[0] | (data
[1] << 8);
3114 return g_strdup_printf ("GotoFrame %u", frame
);
3118 swfdec_action_print_goto_label (guint action
, const guint8
*data
, guint len
)
3120 if (!memchr (data
, 0, len
)) {
3121 SWFDEC_ERROR ("GotoLabel action does not specify a string");
3125 return g_strdup_printf ("GotoLabel %s", data
);
3129 swfdec_action_print_wait_for_frame (guint action
, const guint8
*data
, guint len
)
3136 frame
= data
[0] | (data
[1] << 8);
3138 return g_strdup_printf ("WaitForFrame %u %u", frame
, jump
);
3141 /*** BIG FUNCTION TABLE ***/
3143 const SwfdecActionSpec swfdec_as_actions
[256] = {
3145 [SWFDEC_AS_ACTION_END
] = { "End", NULL
, 0, 0, swfdec_action_end
, 1 },
3146 [SWFDEC_AS_ACTION_NEXT_FRAME
] = { "NextFrame", NULL
, 0, 0, swfdec_action_next_frame
, 1 },
3147 [SWFDEC_AS_ACTION_PREVIOUS_FRAME
] = { "PreviousFrame", NULL
, 0, 0, swfdec_action_previous_frame
, 1 },
3148 [SWFDEC_AS_ACTION_PLAY
] = { "Play", NULL
, 0, 0, swfdec_action_play
, 1 },
3149 [SWFDEC_AS_ACTION_STOP
] = { "Stop", NULL
, 0, 0, swfdec_action_stop
, 1 },
3150 [SWFDEC_AS_ACTION_TOGGLE_QUALITY
] = { "ToggleQuality", NULL
, -1, -1, NULL
, 1 },
3152 [SWFDEC_AS_ACTION_STOP_SOUNDS
] = { "StopSounds", NULL
, 0, 0, swfdec_action_stop_sounds
, 2 },
3154 [SWFDEC_AS_ACTION_ADD
] = { "Add", NULL
, 2, 1, swfdec_action_binary
, 4 },
3155 [SWFDEC_AS_ACTION_SUBTRACT
] = { "Subtract", NULL
, 2, 1, swfdec_action_binary
, 4 },
3156 [SWFDEC_AS_ACTION_MULTIPLY
] = { "Multiply", NULL
, 2, 1, swfdec_action_binary
, 4 },
3157 [SWFDEC_AS_ACTION_DIVIDE
] = { "Divide", NULL
, 2, 1, swfdec_action_binary
, 4 },
3158 [SWFDEC_AS_ACTION_EQUALS
] = { "Equals", NULL
, 2, 1, swfdec_action_old_compare
, 4 },
3159 [SWFDEC_AS_ACTION_LESS
] = { "Less", NULL
, 2, 1, swfdec_action_old_compare
, 4 },
3160 [SWFDEC_AS_ACTION_AND
] = { "And", NULL
, 2, 1, swfdec_action_logical
, 4 },
3161 [SWFDEC_AS_ACTION_OR
] = { "Or", NULL
, 2, 1, swfdec_action_logical
, 4 },
3162 [SWFDEC_AS_ACTION_NOT
] = { "Not", NULL
, 1, 1, swfdec_action_not
, 4 },
3163 [SWFDEC_AS_ACTION_STRING_EQUALS
] = { "StringEquals", NULL
, 2, 1, swfdec_action_string_compare
, 4 },
3164 [SWFDEC_AS_ACTION_STRING_LENGTH
] = { "StringLength", NULL
, 1, 1, swfdec_action_string_length
, 4 },
3165 [SWFDEC_AS_ACTION_STRING_EXTRACT
] = { "StringExtract", NULL
, 3, 1, swfdec_action_string_extract
, 4 },
3166 [SWFDEC_AS_ACTION_POP
] = { "Pop", NULL
, 1, 0, swfdec_action_pop
, 4 },
3167 [SWFDEC_AS_ACTION_TO_INTEGER
] = { "ToInteger", NULL
, 1, 1, swfdec_action_to_integer
, 4 },
3168 [SWFDEC_AS_ACTION_GET_VARIABLE
] = { "GetVariable", NULL
, 1, 1, swfdec_action_get_variable
, 4 },
3169 [SWFDEC_AS_ACTION_SET_VARIABLE
] = { "SetVariable", NULL
, 2, 0, swfdec_action_set_variable
, 4 },
3171 [SWFDEC_AS_ACTION_SET_TARGET2
] = { "SetTarget2", NULL
, 1, 0, swfdec_action_set_target2
, 3 },
3173 [SWFDEC_AS_ACTION_STRING_ADD
] = { "StringAdd", NULL
, 2, 1, swfdec_action_string_add
, 4 },
3174 [SWFDEC_AS_ACTION_GET_PROPERTY
] = { "GetProperty", NULL
, 2, 1, swfdec_action_get_property
, 4 },
3175 [SWFDEC_AS_ACTION_SET_PROPERTY
] = { "SetProperty", NULL
, 3, 0, swfdec_action_set_property
, 4 },
3176 [SWFDEC_AS_ACTION_CLONE_SPRITE
] = { "CloneSprite", NULL
, 3, 0, swfdec_action_clone_sprite
, 4 },
3177 [SWFDEC_AS_ACTION_REMOVE_SPRITE
] = { "RemoveSprite", NULL
, 1, 0, swfdec_action_remove_sprite
, 4 },
3178 [SWFDEC_AS_ACTION_TRACE
] = { "Trace", NULL
, 1, 0, swfdec_action_trace
, 4 },
3179 [SWFDEC_AS_ACTION_START_DRAG
] = { "StartDrag", NULL
, -1, 0, swfdec_action_start_drag
, 4 },
3180 [SWFDEC_AS_ACTION_END_DRAG
] = { "EndDrag", NULL
, 0, 0, swfdec_action_end_drag
, 4 },
3181 [SWFDEC_AS_ACTION_STRING_LESS
] = { "StringLess", NULL
, 2, 1, swfdec_action_string_compare
, 4 },
3183 [SWFDEC_AS_ACTION_THROW
] = { "Throw", NULL
, 1, 0, swfdec_action_throw
, 7 },
3184 [SWFDEC_AS_ACTION_CAST
] = { "Cast", NULL
, 2, 1, swfdec_action_cast
, 7 },
3185 [SWFDEC_AS_ACTION_IMPLEMENTS
] = { "Implements", NULL
, -1, 0, swfdec_action_implements
, 7 },
3187 [SWFDEC_AS_ACTION_RANDOM
] = { "RandomNumber", NULL
, 1, 1, swfdec_action_random_number
, 4 },
3188 [SWFDEC_AS_ACTION_MB_STRING_LENGTH
] = { "MBStringLength", NULL
, 1, 1, swfdec_action_string_length
, 4 },
3189 [SWFDEC_AS_ACTION_CHAR_TO_ASCII
] = { "CharToAscii", NULL
, 1, 1, swfdec_action_char_to_ascii
, 4 },
3190 [SWFDEC_AS_ACTION_ASCII_TO_CHAR
] = { "AsciiToChar", NULL
, 1, 1, swfdec_action_ascii_to_char
, 4 },
3191 [SWFDEC_AS_ACTION_GET_TIME
] = { "GetTime", NULL
, 0, 1, swfdec_action_get_time
, 4 },
3192 [SWFDEC_AS_ACTION_MB_STRING_EXTRACT
] = { "MBStringExtract", NULL
, 3, 1, swfdec_action_string_extract
, 4 },
3193 [SWFDEC_AS_ACTION_MB_CHAR_TO_ASCII
] = { "MBCharToAscii", NULL
, 1, 1, swfdec_action_char_to_ascii
, 4 },
3194 [SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
] = { "MBAsciiToChar", NULL
, 1, 1, swfdec_action_ascii_to_char
, 4 },
3196 [SWFDEC_AS_ACTION_DELETE
] = { "Delete", NULL
, 2, 1, swfdec_action_delete
, 5 },
3197 [SWFDEC_AS_ACTION_DELETE2
] = { "Delete2", NULL
, 1, 1, swfdec_action_delete2
, 5 },
3198 [SWFDEC_AS_ACTION_DEFINE_LOCAL
] = { "DefineLocal", NULL
, 2, 0, swfdec_action_define_local
, 5 },
3199 [SWFDEC_AS_ACTION_CALL_FUNCTION
] = { "CallFunction", NULL
, -1, 1, swfdec_action_call_function
, 5 },
3200 [SWFDEC_AS_ACTION_RETURN
] = { "Return", NULL
, 1, 0, swfdec_action_return
, 5 },
3201 [SWFDEC_AS_ACTION_MODULO
] = { "Modulo", NULL
, 2, 1, swfdec_action_modulo
, 5 },
3202 [SWFDEC_AS_ACTION_NEW_OBJECT
] = { "NewObject", NULL
, -1, 1, swfdec_action_new_object
, 5 },
3203 [SWFDEC_AS_ACTION_DEFINE_LOCAL2
] = { "DefineLocal2", NULL
, 1, 0, swfdec_action_define_local2
, 5 },
3204 [SWFDEC_AS_ACTION_INIT_ARRAY
] = { "InitArray", NULL
, -1, 1, swfdec_action_init_array
, 5 },
3205 [SWFDEC_AS_ACTION_INIT_OBJECT
] = { "InitObject", NULL
, -1, 1, swfdec_action_init_object
, 5 },
3206 [SWFDEC_AS_ACTION_TYPE_OF
] = { "TypeOf", NULL
, 1, 1, swfdec_action_type_of
, 5 },
3207 [SWFDEC_AS_ACTION_TARGET_PATH
] = { "TargetPath", NULL
, 1, 1, swfdec_action_target_path
, 5 },
3208 [SWFDEC_AS_ACTION_ENUMERATE
] = { "Enumerate", NULL
, 1, -1, swfdec_action_enumerate
, 5 },
3209 [SWFDEC_AS_ACTION_ADD2
] = { "Add2", NULL
, 2, 1, swfdec_action_add2
, 5 },
3210 [SWFDEC_AS_ACTION_LESS2
] = { "Less2", NULL
, 2, 1, swfdec_action_new_comparison
, 5 },
3211 [SWFDEC_AS_ACTION_EQUALS2
] = { "Equals2", NULL
, 2, 1, swfdec_action_equals2
, 5 },
3212 [SWFDEC_AS_ACTION_TO_NUMBER
] = { "ToNumber", NULL
, 1, 1, swfdec_action_to_number
, 5 },
3213 [SWFDEC_AS_ACTION_TO_STRING
] = { "ToString", NULL
, 1, 1, swfdec_action_to_string
, 5 },
3214 [SWFDEC_AS_ACTION_PUSH_DUPLICATE
] = { "PushDuplicate", NULL
, 1, 2, swfdec_action_push_duplicate
, 5 },
3215 [SWFDEC_AS_ACTION_SWAP
] = { "Swap", NULL
, 2, 2, swfdec_action_swap
, 5 },
3217 [SWFDEC_AS_ACTION_GET_MEMBER
] = { "GetMember", NULL
, 2, 1, swfdec_action_get_member
, 4 },
3218 [SWFDEC_AS_ACTION_SET_MEMBER
] = { "SetMember", NULL
, 3, 0, swfdec_action_set_member
, 4 },
3220 [SWFDEC_AS_ACTION_INCREMENT
] = { "Increment", NULL
, 1, 1, swfdec_action_increment
, 5 },
3221 [SWFDEC_AS_ACTION_DECREMENT
] = { "Decrement", NULL
, 1, 1, swfdec_action_decrement
, 5 },
3222 [SWFDEC_AS_ACTION_CALL_METHOD
] = { "CallMethod", NULL
, -1, 1, swfdec_action_call_method
, 5 },
3223 [SWFDEC_AS_ACTION_NEW_METHOD
] = { "NewMethod", NULL
, -1, 1, swfdec_action_new_method
, 5 },
3225 [SWFDEC_AS_ACTION_INSTANCE_OF
] = { "InstanceOf", NULL
, 2, 1, swfdec_action_instance_of
, 6 },
3226 [SWFDEC_AS_ACTION_ENUMERATE2
] = { "Enumerate2", NULL
, 1, -1, swfdec_action_enumerate2
, 6 },
3227 [SWFDEC_AS_ACTION_BREAKPOINT
] = { "Breakpoint", NULL
, -1, -1, NULL
, 6 },
3229 [SWFDEC_AS_ACTION_BIT_AND
] = { "BitAnd", NULL
, 2, 1, swfdec_action_bitwise
, 5 },
3230 [SWFDEC_AS_ACTION_BIT_OR
] = { "BitOr", NULL
, 2, 1, swfdec_action_bitwise
, 5 },
3231 [SWFDEC_AS_ACTION_BIT_XOR
] = { "BitXor", NULL
, 2, 1, swfdec_action_bitwise
, 5 },
3232 [SWFDEC_AS_ACTION_BIT_LSHIFT
] = { "BitLShift", NULL
, 2, 1, swfdec_action_shift
, 5 },
3233 [SWFDEC_AS_ACTION_BIT_RSHIFT
] = { "BitRShift", NULL
, 2, 1, swfdec_action_shift
, 5 },
3234 [SWFDEC_AS_ACTION_BIT_URSHIFT
] = { "BitURShift", NULL
, 2, 1, swfdec_action_shift
, 5 },
3236 [SWFDEC_AS_ACTION_STRICT_EQUALS
] = { "StrictEquals", NULL
, 2, 1, swfdec_action_strict_equals
, 6 },
3237 [SWFDEC_AS_ACTION_GREATER
] = { "Greater", NULL
, 2, 1, swfdec_action_new_comparison
, 6 },
3238 [SWFDEC_AS_ACTION_STRING_GREATER
] = { "StringGreater", NULL
, 2, 1, swfdec_action_string_compare
, 6 },
3240 [SWFDEC_AS_ACTION_EXTENDS
] = { "Extends", NULL
, 2, 0, swfdec_action_extends
, 7 },
3242 [SWFDEC_AS_ACTION_GOTO_FRAME
] = { "GotoFrame", swfdec_action_print_goto_frame
, 0, 0, swfdec_action_goto_frame
, 1 },
3243 [SWFDEC_AS_ACTION_GET_URL
] = { "GetURL", swfdec_action_print_get_url
, 0, 0, swfdec_action_get_url
, 1 },
3245 [SWFDEC_AS_ACTION_STORE_REGISTER
] = { "StoreRegister", swfdec_action_print_store_register
, 1, 1, swfdec_action_store_register
, 5 },
3246 [SWFDEC_AS_ACTION_CONSTANT_POOL
] = { "ConstantPool", swfdec_action_print_constant_pool
, 0, 0, swfdec_action_constant_pool
, 5 },
3247 [SWFDEC_AS_ACTION_STRICT_MODE
] = { "StrictMode", NULL
, -1, -1, NULL
, 5 },
3249 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME
] = { "WaitForFrame", swfdec_action_print_wait_for_frame
, 0, 0, swfdec_action_wait_for_frame
, 1 },
3250 [SWFDEC_AS_ACTION_SET_TARGET
] = { "SetTarget", swfdec_action_print_set_target
, 0, 0, swfdec_action_set_target
, 1 },
3252 [SWFDEC_AS_ACTION_GOTO_LABEL
] = { "GotoLabel", swfdec_action_print_goto_label
, 0, 0, swfdec_action_goto_label
, 3 },
3254 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME2
] = { "WaitForFrame2", swfdec_action_print_wait_for_frame2
, 1, 0, swfdec_action_wait_for_frame2
, 4 },
3256 [SWFDEC_AS_ACTION_DEFINE_FUNCTION2
] = { "DefineFunction2", swfdec_action_print_define_function
, 0, -1, swfdec_action_define_function
, 7 },
3257 [SWFDEC_AS_ACTION_TRY
] = { "Try", NULL
, 0, 0, swfdec_action_try
, 7 },
3259 [SWFDEC_AS_ACTION_WITH
] = { "With", swfdec_action_print_with
, 1, 0, swfdec_action_with
, 5 },
3261 [SWFDEC_AS_ACTION_PUSH
] = { "Push", swfdec_action_print_push
, 0, -1, swfdec_action_push
, 4 },
3262 [SWFDEC_AS_ACTION_JUMP
] = { "Jump", swfdec_action_print_jump
, 0, 0, swfdec_action_jump
, 4 },
3263 [SWFDEC_AS_ACTION_GET_URL2
] = { "GetURL2", swfdec_action_print_get_url2
, 2, 0, swfdec_action_get_url2
, 4 },
3265 [SWFDEC_AS_ACTION_DEFINE_FUNCTION
] = { "DefineFunction", swfdec_action_print_define_function
, 0, -1, swfdec_action_define_function
, 5 },
3267 [SWFDEC_AS_ACTION_IF
] = { "If", swfdec_action_print_if
, 1, 0, swfdec_action_if
, 4 },
3268 [SWFDEC_AS_ACTION_CALL
] = { "Call", NULL
, -1, -1, NULL
, 4 },
3269 [SWFDEC_AS_ACTION_GOTO_FRAME2
] = { "GotoFrame2", swfdec_action_print_goto_frame2
, 1, 0, swfdec_action_goto_frame2
, 4 }