2 * Copyright (C) 2007 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_frame_internal.h"
28 #include "swfdec_as_function.h"
29 #include "swfdec_as_script_function.h"
30 #include "swfdec_as_stack.h"
31 #include "swfdec_as_string.h"
32 #include "swfdec_as_strings.h"
33 #include "swfdec_as_super.h"
34 #include "swfdec_as_internal.h"
35 #include "swfdec_debug.h"
40 #include "swfdec_decoder.h"
41 #include "swfdec_movie.h"
42 #include "swfdec_player_internal.h"
43 #include "swfdec_sprite.h"
44 #include "swfdec_sprite_movie.h"
45 #include "swfdec_resource.h"
46 #include "swfdec_resource_request.h"
47 #include "swfdec_text_field_movie.h" // for typeof
49 /* Define this to get SWFDEC_WARN'd about missing properties of objects.
50 * This can be useful to find out about unimplemented native properties,
51 * but usually just causes a lot of spam. */
52 //#define SWFDEC_WARN_MISSING_PROPERTIES
54 /*** SUPPORT FUNCTIONS ***/
56 #define swfdec_action_has_register(cx, i) \
57 ((i) < (cx)->frame->n_registers)
59 /*** ALL THE ACTION IS HERE ***/
62 swfdec_action_stop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
64 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
65 SWFDEC_SPRITE_MOVIE (cx
->frame
->target
)->playing
= FALSE
;
67 SWFDEC_ERROR ("no movie to stop");
71 swfdec_action_play (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
73 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
))
74 SWFDEC_SPRITE_MOVIE (cx
->frame
->target
)->playing
= TRUE
;
76 SWFDEC_ERROR ("no movie to play");
80 swfdec_action_next_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
82 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
83 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
84 if (movie
->frame
< movie
->n_frames
) {
85 swfdec_sprite_movie_goto (movie
, movie
->frame
+ 1);
87 SWFDEC_INFO ("can't execute nextFrame, already at last frame");
90 SWFDEC_ERROR ("no movie to nextFrame on");
95 swfdec_action_previous_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
97 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
98 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
99 if (movie
->frame
> 1) {
100 swfdec_sprite_movie_goto (movie
, movie
->frame
- 1);
102 SWFDEC_INFO ("can't execute previousFrame, already at first frame");
105 SWFDEC_ERROR ("no movie to previousFrame on");
110 swfdec_action_goto_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
115 SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len
);
118 frame
= GUINT16_FROM_LE (*((guint16
*) data
));
119 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
120 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
121 swfdec_sprite_movie_goto (movie
, frame
+ 1);
122 movie
->playing
= FALSE
;
124 SWFDEC_ERROR ("no movie to goto on");
129 swfdec_action_goto_label (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
131 if (!memchr (data
, 0, len
)) {
132 SWFDEC_ERROR ("GotoLabel action does not specify a string");
136 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
137 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
139 if (movie
->sprite
== NULL
||
140 (frame
= swfdec_sprite_get_frame (movie
->sprite
, (const char *) data
)) == -1)
142 swfdec_sprite_movie_goto (movie
, frame
+ 1);
143 movie
->playing
= FALSE
;
145 SWFDEC_ERROR ("no movie to goto on");
149 /* returns: frame to go to or 0 on error */
151 swfdec_value_to_frame (SwfdecAsContext
*cx
, SwfdecSpriteMovie
*movie
, SwfdecAsValue
*val
)
155 if (movie
->sprite
== NULL
)
157 if (SWFDEC_AS_VALUE_IS_STRING (val
)) {
158 const char *name
= SWFDEC_AS_VALUE_GET_STRING (val
);
160 if (strchr (name
, ':')) {
161 SWFDEC_ERROR ("FIXME: handle targets");
163 /* treat valid encoded numbers as numbers, otherwise assume it's a frame label */
164 d
= swfdec_as_value_to_number (cx
, val
);
166 frame
= swfdec_sprite_get_frame (movie
->sprite
, name
) + 1;
169 } else if (SWFDEC_AS_VALUE_IS_NUMBER (val
)) {
170 frame
= swfdec_as_value_to_integer (cx
, val
);
172 SWFDEC_WARNING ("cannot convert value to frame number");
173 /* FIXME: how do we treat undefined etc? */
176 return frame
<= 0 ? 0 : frame
;
180 swfdec_action_goto_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
187 swfdec_bits_init_data (&bits
, data
, len
);
188 if (swfdec_bits_getbits (&bits
, 6)) {
189 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
191 bias
= swfdec_bits_getbit (&bits
);
192 play
= swfdec_bits_getbit (&bits
);
194 bias
= swfdec_bits_get_u16 (&bits
);
196 val
= swfdec_as_stack_peek (cx
, 1);
198 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
199 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
200 guint frame
= swfdec_value_to_frame (cx
, movie
, val
);
203 frame
= CLAMP (frame
, 1, movie
->n_frames
);
204 swfdec_sprite_movie_goto (movie
, frame
);
205 movie
->playing
= play
;
208 SWFDEC_ERROR ("no movie to GotoFrame2 on");
210 swfdec_as_stack_pop (cx
);
214 swfdec_script_skip_actions (SwfdecAsContext
*cx
, guint jump
)
216 SwfdecScript
*script
= cx
->frame
->script
;
217 const guint8
*pc
= cx
->frame
->pc
;
218 const guint8
*endpc
= script
->buffer
->data
+ script
->buffer
->length
;
220 /* jump instructions */
227 pc
+= 3 + GUINT16_FROM_LE (*((guint16
*) (pc
+ 1)));
231 } while (jump
-- > 0);
237 swfdec_action_wait_for_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
242 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
245 val
= cx
->fp
->sp
[-1];
247 if (SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
248 SwfdecMovie
*movie
= SWFDEC_MOVIE (cx
->frame
->target
);
249 int frame
= swfdec_value_to_frame (cx
, movie
, val
);
250 guint jump
= data
[2];
254 if (SWFDEC_IS_ROOT_MOVIE (movie
)) {
255 SwfdecDecoder
*dec
= SWFDEC_ROOT_MOVIE (movie
)->decoder
;
256 loaded
= dec
->frames_loaded
;
257 g_assert (loaded
<= movie
->n_frames
);
259 loaded
= movie
->n_frames
;
261 if (loaded
<= (guint
) frame
)
262 swfdec_script_skip_actions (cx
, jump
);
264 SWFDEC_ERROR ("no movie to WaitForFrame2 on");
271 swfdec_action_wait_for_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
273 SwfdecSpriteMovie
*movie
;
278 SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len
);
281 if (!SWFDEC_IS_SPRITE_MOVIE (cx
->frame
->target
)) {
282 SWFDEC_ERROR ("no movie for WaitForFrame");
286 movie
= SWFDEC_SPRITE_MOVIE (cx
->frame
->target
);
287 frame
= data
[0] || (data
[1] << 8);
289 loaded
= swfdec_sprite_movie_get_frames_loaded (movie
);
290 if (loaded
< (int) movie
->n_frames
&&
292 swfdec_script_skip_actions (cx
, jump
);
296 swfdec_action_constant_pool (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
298 SwfdecConstantPool
*pool
;
299 SwfdecAsFrame
*frame
;
302 pool
= swfdec_constant_pool_new_from_action (data
, len
, cx
->version
);
305 swfdec_constant_pool_attach_to_context (pool
, cx
);
306 if (frame
->constant_pool
)
307 swfdec_constant_pool_free (frame
->constant_pool
);
308 frame
->constant_pool
= pool
;
309 if (frame
->constant_pool_buffer
)
310 swfdec_buffer_unref (frame
->constant_pool_buffer
);
311 frame
->constant_pool_buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
312 data
- frame
->script
->buffer
->data
, len
);
316 swfdec_action_push (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
320 swfdec_bits_init_data (&bits
, data
, len
);
321 while (swfdec_bits_left (&bits
)) {
322 guint type
= swfdec_bits_get_u8 (&bits
);
323 SWFDEC_LOG ("push type %u", type
);
324 swfdec_as_stack_ensure_free (cx
, 1);
328 char *s
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
331 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
332 swfdec_as_context_give_string (cx
, s
));
336 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_push (cx
),
337 swfdec_bits_get_float (&bits
));
340 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
342 case 3: /* undefined */
343 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
345 case 4: /* register */
347 guint regnum
= swfdec_bits_get_u8 (&bits
);
348 if (!swfdec_action_has_register (cx
, regnum
)) {
349 SWFDEC_ERROR ("cannot Push register %u: not enough registers", regnum
);
350 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
352 *swfdec_as_stack_push (cx
) = cx
->frame
->registers
[regnum
];
356 case 5: /* boolean */
357 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
358 swfdec_bits_get_u8 (&bits
) ? TRUE
: FALSE
);
361 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_push (cx
),
362 swfdec_bits_get_double (&bits
));
364 case 7: /* 32bit int */
365 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_push (cx
),
366 (int) swfdec_bits_get_u32 (&bits
));
368 case 8: /* 8bit ConstantPool address */
370 guint i
= swfdec_bits_get_u8 (&bits
);
371 SwfdecConstantPool
*pool
= cx
->frame
->constant_pool
;
373 SWFDEC_ERROR ("no constant pool to push from");
376 if (i
>= swfdec_constant_pool_size (pool
)) {
377 SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
378 i
, swfdec_constant_pool_size (pool
));
381 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
382 swfdec_constant_pool_get (pool
, i
));
385 case 9: /* 16bit ConstantPool address */
387 guint i
= swfdec_bits_get_u16 (&bits
);
388 SwfdecConstantPool
*pool
= cx
->frame
->constant_pool
;
390 SWFDEC_ERROR ("no constant pool to push from");
393 if (i
>= swfdec_constant_pool_size (pool
)) {
394 SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
395 i
, swfdec_constant_pool_size (pool
));
398 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
399 swfdec_constant_pool_get (pool
, i
));
403 SWFDEC_ERROR ("Push: type %u not implemented", type
);
409 /* NB: name must be GC'd */
410 static SwfdecAsObject
*
411 super_special_movie_lookup_magic (SwfdecAsContext
*cx
, SwfdecAsObject
*o
, const char *name
)
416 o
= swfdec_as_frame_get_variable (cx
->frame
, name
, NULL
);
420 if (SWFDEC_IS_MOVIE (o
)) {
421 SwfdecMovie
*ret
= swfdec_movie_get_by_name (SWFDEC_MOVIE (o
), name
, TRUE
);
423 return SWFDEC_AS_OBJECT (ret
);
425 if (!swfdec_as_object_get_variable (o
, name
, &val
))
427 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
429 return SWFDEC_AS_VALUE_GET_OBJECT (&val
);
432 static SwfdecAsObject
*
433 swfdec_action_get_movie_by_slash_path (SwfdecAsContext
*cx
, const char *path
)
437 o
= cx
->frame
->target
;
438 if (!SWFDEC_IS_MOVIE (o
))
441 o
= SWFDEC_AS_OBJECT (swfdec_movie_get_root (SWFDEC_MOVIE (o
)));
445 char *slash
= strchr (path
, '/');
450 name
= swfdec_as_context_give_string (cx
, g_strndup (path
, slash
- path
));
453 name
= swfdec_as_context_get_string (cx
, path
);
454 path
+= strlen (path
);
456 o
= super_special_movie_lookup_magic (cx
, o
, name
);
457 if (!SWFDEC_IS_MOVIE (o
))
464 swfdec_action_lookup_object (SwfdecAsContext
*cx
, SwfdecAsObject
*o
, const char *path
, const char *end
)
466 gboolean dot_allowed
= TRUE
;
471 o
= cx
->frame
->target
;
472 if (SWFDEC_IS_MOVIE (o
))
478 if (path
[0] == '/') {
480 o
= cx
->frame
->target
;
481 if (!SWFDEC_IS_MOVIE (o
))
483 o
= SWFDEC_AS_OBJECT (swfdec_movie_get_root (SWFDEC_MOVIE (o
)));
488 for (start
= path
; path
< end
; path
++) {
489 if (dot_allowed
&& path
[0] == '.') {
490 if (end
- path
>= 2 && path
[1] == '.') {
494 } else if (path
[0] == ':') {
501 } else if (path
[0] == '/') {
503 } else if (path
- start
< 127) {
511 if (start
[0] == '.' && start
[1] == '.' && start
+ 2 == path
) {
514 for (walk
= cx
->frame
->scope_chain
; walk
; walk
= walk
->next
) {
515 if (SWFDEC_IS_MOVIE (walk
->data
)) {
521 o
= cx
->frame
->target
;
523 /* ".." goes back to parent */
524 if (!SWFDEC_IS_MOVIE (o
))
526 o
= SWFDEC_AS_OBJECT (SWFDEC_MOVIE (o
)->parent
);
530 o
= super_special_movie_lookup_magic (cx
, o
,
531 swfdec_as_context_give_string (cx
, g_strndup (start
, path
- start
)));
535 if (path
- start
< 127)
542 /* FIXME: this function belongs into swfdec_movie.c */
544 swfdec_player_get_movie_from_value (SwfdecPlayer
*player
, SwfdecAsValue
*val
)
549 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
550 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (val
), NULL
);
552 cx
= SWFDEC_AS_CONTEXT (player
);
553 s
= swfdec_as_value_to_string (cx
, val
);
554 return swfdec_player_get_movie_from_string (player
, s
);
558 swfdec_player_get_movie_from_string (SwfdecPlayer
*player
, const char *s
)
562 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
563 g_return_val_if_fail (s
!= NULL
, NULL
);
565 ret
= swfdec_action_lookup_object (SWFDEC_AS_CONTEXT (player
), NULL
, s
, s
+ strlen (s
));
566 if (!SWFDEC_IS_MOVIE (ret
)) {
567 SWFDEC_WARNING ("\"%s\" does not reference a movie", s
);
570 return SWFDEC_MOVIE (ret
);
574 * swfdec_action_get_movie_by_path:
575 * @cx: a #SwfdecAsContext
576 * @path: the path to look up
577 * @object: pointer that takes the object that was looked up. The object may be
579 * @variable: pointer that takes variable part of the path. The variable will
580 * be either %NULL or a non-gc'ed variable name.
582 * Looks up a Flash4-compatible path using "/", ":" and "." style syntax.
584 * Returns: The #SwfdecMovie that was looked up or %NULL if the path does not
585 * specify a valid movie.
588 swfdec_action_get_movie_by_path (SwfdecAsContext
*cx
, const char *path
,
589 SwfdecAsObject
**object
, const char **variable
)
591 SwfdecAsObject
*movie
;
594 g_assert (path
!= NULL
);
595 g_assert (object
!= NULL
);
596 g_assert (variable
!= NULL
);
597 g_assert (cx
->frame
!= NULL
);
599 /* find dot or colon */
600 end
= strpbrk (path
, ".:");
602 /* if no dot or colon, look up slash-path */
604 /* shortcut for the general case */
605 if (strchr (path
, '/') != NULL
) {
606 movie
= swfdec_action_get_movie_by_slash_path (cx
, path
);
618 /* find last dot or colon */
619 while ((s
= strpbrk (end
+ 1, ".:")) != NULL
)
622 /* variable to use is the part after the last dot or colon */
624 /* look up object for start of path */
628 movie
= swfdec_action_lookup_object (cx
, NULL
, path
, end
);
639 swfdec_action_get_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
643 SwfdecAsObject
*object
;
645 val
= swfdec_as_stack_peek (cx
, 1);
646 s
= swfdec_as_value_to_string (cx
, val
);
647 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &s
)) {
650 swfdec_as_object_get_variable (object
, swfdec_as_context_get_string (cx
, s
), val
);
652 SWFDEC_AS_VALUE_SET_OBJECT (val
, object
);
655 swfdec_as_frame_get_variable (cx
->frame
, swfdec_as_context_get_string (cx
, s
), val
);
658 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
659 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
660 SWFDEC_WARNING ("no variable named %s", s
);
666 swfdec_action_set_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
668 const char *s
, *rest
;
669 SwfdecAsObject
*object
;
671 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
672 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &rest
)) {
673 if (object
&& rest
) {
674 swfdec_as_object_set_variable (object
, swfdec_as_context_get_string (cx
, rest
),
675 swfdec_as_stack_peek (cx
, 1));
680 rest
= swfdec_as_context_get_string (cx
, rest
);
681 swfdec_as_frame_set_variable (cx
->frame
, rest
, swfdec_as_stack_peek (cx
, 1));
684 swfdec_as_stack_pop_n (cx
, 2);
687 /* FIXME: this sucks */
689 gboolean needs_movie
;
690 const char * name
; /* GC'd */
691 void (* get
) (SwfdecMovie
*movie
, SwfdecAsValue
*ret
);
692 void (* set
) (SwfdecMovie
*movie
, const SwfdecAsValue
*val
);
693 } swfdec_movieclip_props
[];
695 swfdec_action_get_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
700 id
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
701 if (!SWFDEC_IS_PLAYER (cx
)) {
702 SWFDEC_INFO ("tried using GetProperty in a non-SwfdecPlayer context");
705 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
706 swfdec_as_stack_peek (cx
, 2));
710 if (id
> (cx
->version
> 4 ? 21 : 18)) {
711 SWFDEC_WARNING ("trying to SetProperty %u, doesn't exist", id
);
714 swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (movie
), swfdec_movieclip_props
[id
].name
,
715 swfdec_as_stack_peek (cx
, 2));
716 swfdec_as_stack_pop (cx
);
720 swfdec_as_stack_pop (cx
);
721 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
725 swfdec_action_set_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
730 id
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
731 if (!SWFDEC_IS_PLAYER (cx
)) {
732 SWFDEC_INFO ("tried using GetProperty in a non-SwfdecPlayer context");
735 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
736 swfdec_as_stack_peek (cx
, 3));
740 if (id
> (cx
->version
> 4 ? 21 : 18)) {
741 SWFDEC_WARNING ("trying to SetProperty %u, doesn't exist", id
);
744 swfdec_as_object_set_variable (SWFDEC_AS_OBJECT (movie
), swfdec_movieclip_props
[id
].name
,
745 swfdec_as_stack_peek (cx
, 1));
746 swfdec_as_stack_pop_n (cx
, 3);
750 swfdec_as_stack_pop_n (cx
, 3);
754 swfdec_action_get_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
756 SwfdecAsObject
*object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 2));
759 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
760 swfdec_as_object_get_variable (object
, name
, swfdec_as_stack_peek (cx
, 2));
761 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
762 if (SWFDEC_AS_VALUE_IS_UNDEFINED (swfdec_as_stack_peek (cx
, 2))) {
763 SWFDEC_WARNING ("no variable named %s:%s", G_OBJECT_TYPE_NAME (object
), name
);
767 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
769 swfdec_as_stack_pop (cx
);
773 swfdec_action_set_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
775 if (SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 3))) {
776 const char *name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
777 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 3)),
778 name
, swfdec_as_stack_peek (cx
, 1));
780 swfdec_as_stack_pop_n (cx
, 3);
784 swfdec_action_trace (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
789 val
= swfdec_as_stack_peek (cx
, 1);
790 if (val
->type
== SWFDEC_AS_TYPE_UNDEFINED
) {
791 s
= SWFDEC_AS_STR_undefined
;
792 } else if (val
->type
== SWFDEC_AS_TYPE_OBJECT
&&
793 SWFDEC_IS_AS_STRING (swfdec_as_value_to_object (cx
, val
))) {
794 s
= SWFDEC_AS_STRING (swfdec_as_value_to_object (cx
, val
))->string
;
796 s
= swfdec_as_value_to_string (cx
, val
);
798 swfdec_as_stack_pop (cx
);
799 g_signal_emit_by_name (cx
, "trace", s
);
802 /* stack looks like this: [ function, this, arg1, arg2, ... ] */
803 /* stack must be at least 2 elements big */
805 swfdec_action_call (SwfdecAsContext
*cx
, guint n_args
)
807 SwfdecAsFunction
*fun
;
808 SwfdecAsObject
*thisp
;
810 if (!SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 1)))
812 fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 1));
813 if (!SWFDEC_IS_AS_FUNCTION (fun
))
815 if (!SWFDEC_AS_VALUE_IS_OBJECT (swfdec_as_stack_peek (cx
, 2))) {
818 thisp
= SWFDEC_AS_VALUE_GET_OBJECT (swfdec_as_stack_peek (cx
, 2));
820 swfdec_as_stack_pop_n (cx
, 2);
821 /* sanitize argument count */
822 if (n_args
>= swfdec_as_stack_get_size (cx
))
823 n_args
= swfdec_as_stack_get_size (cx
);
824 swfdec_as_function_call (fun
, thisp
, n_args
, NULL
, NULL
);
825 if (SWFDEC_IS_AS_SUPER (fun
)) {
826 SWFDEC_LOG ("replacing super object on frame");
827 swfdec_as_super_replace (SWFDEC_AS_SUPER (fun
), NULL
);
833 if (n_args
> swfdec_as_stack_get_size (cx
))
834 n_args
= swfdec_as_stack_get_size (cx
);
835 swfdec_as_stack_pop_n (cx
, n_args
);
836 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
841 swfdec_action_call_function (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
843 SwfdecAsFrame
*frame
= cx
->frame
;
847 SwfdecAsValue
*fun
, *thisp
;
849 swfdec_as_stack_ensure_size (cx
, 2);
850 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
851 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
852 thisp
= swfdec_as_stack_peek (cx
, 2);
853 fun
= swfdec_as_stack_peek (cx
, 1);
854 obj
= swfdec_as_frame_get_variable (frame
, name
, fun
);
856 SWFDEC_AS_VALUE_SET_OBJECT (thisp
, obj
);
858 SWFDEC_AS_VALUE_SET_NULL (thisp
);
859 SWFDEC_AS_VALUE_SET_UNDEFINED (fun
);
861 if (!swfdec_action_call (cx
, n_args
)) {
862 SWFDEC_WARNING ("no function named %s", name
);
867 swfdec_action_call_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
869 SwfdecAsFrame
*frame
= cx
->frame
;
873 const char *name
= NULL
;
875 swfdec_as_stack_ensure_size (cx
, 3);
876 obj
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 2));
877 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
878 val
= swfdec_as_stack_peek (cx
, 1);
879 /* FIXME: this is a hack for constructors calling super - is this correct? */
880 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val
)) {
881 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
884 if (SWFDEC_AS_VALUE_IS_STRING (val
) &&
885 SWFDEC_AS_VALUE_GET_STRING (val
) == SWFDEC_AS_STR_EMPTY
) {
886 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 3));
887 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 2), obj
);
889 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_peek (cx
, 3), obj
);
890 name
= swfdec_as_value_to_string (cx
, val
);
891 swfdec_as_object_get_variable (obj
, name
, swfdec_as_stack_peek (cx
, 2));
894 if (SWFDEC_AS_VALUE_IS_STRING (val
))
895 name
= SWFDEC_AS_VALUE_GET_STRING (val
);
896 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_peek (cx
, 3));
897 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
899 swfdec_as_stack_pop (cx
);
900 if (swfdec_action_call (cx
, n_args
)) {
901 /* setup super to point to the right prototype */
903 if (SWFDEC_IS_AS_SUPER (obj
)) {
904 swfdec_as_super_replace (SWFDEC_AS_SUPER (obj
), name
);
905 } else if (frame
->super
) {
906 SwfdecAsSuper
*super
= SWFDEC_AS_SUPER (frame
->super
);
909 swfdec_as_object_get_variable_and_flags (frame
->thisp
,
910 name
, NULL
, NULL
, &super
->object
) &&
911 super
->object
== frame
->thisp
) {
912 // FIXME: Do we need to check prototype_flags here?
913 super
->object
= super
->object
->prototype
;
917 SWFDEC_WARNING ("no function named %s on object %s", name
? name
: "unknown", obj
? G_OBJECT_TYPE_NAME(obj
) : "unknown");
922 swfdec_action_pop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
924 swfdec_as_stack_pop (cx
);
928 swfdec_action_binary (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
932 r
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
933 l
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
935 case SWFDEC_AS_ACTION_ADD
:
938 case SWFDEC_AS_ACTION_SUBTRACT
:
941 case SWFDEC_AS_ACTION_MULTIPLY
:
944 case SWFDEC_AS_ACTION_DIVIDE
:
945 if (cx
->version
< 5) {
947 swfdec_as_stack_pop (cx
);
948 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR__ERROR_
);
964 g_assert_not_reached ();
967 swfdec_as_stack_pop (cx
);
968 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), l
);
972 swfdec_action_add2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
974 SwfdecAsValue
*rval
, *lval
, rtmp
, ltmp
;
976 rval
= swfdec_as_stack_peek (cx
, 1);
977 lval
= swfdec_as_stack_peek (cx
, 2);
980 swfdec_as_value_to_primitive (&rtmp
);
981 if (!SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
) || SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
)))
983 swfdec_as_value_to_primitive (<mp
);
984 if (!SWFDEC_AS_VALUE_IS_OBJECT (<mp
) || SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (<mp
)))
987 if (SWFDEC_AS_VALUE_IS_STRING (lval
) || SWFDEC_AS_VALUE_IS_STRING (rval
)) {
988 const char *lstr
, *rstr
;
989 lstr
= swfdec_as_value_to_string (cx
, lval
);
990 rstr
= swfdec_as_value_to_string (cx
, rval
);
991 lstr
= swfdec_as_str_concat (cx
, lstr
, rstr
);
992 swfdec_as_stack_pop (cx
);
993 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), lstr
);
996 d
= swfdec_as_value_to_number (cx
, lval
);
997 d2
= swfdec_as_value_to_number (cx
, rval
);
999 swfdec_as_stack_pop (cx
);
1000 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), d
);
1005 swfdec_action_new_comparison (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1007 SwfdecAsValue
*lval
, *rval
;
1010 rval
= swfdec_as_stack_peek (cx
, 1);
1011 lval
= swfdec_as_stack_peek (cx
, 2);
1013 /* swap if we do a greater comparison */
1014 if (action
== SWFDEC_AS_ACTION_GREATER
) {
1015 SwfdecAsValue
*tmp
= lval
;
1019 /* comparison with object is always false */
1020 swfdec_as_value_to_primitive (lval
);
1021 if (SWFDEC_AS_VALUE_IS_OBJECT (lval
) &&
1022 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (lval
))) {
1023 swfdec_as_stack_pop (cx
);
1024 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
1027 /* same for the rval */
1028 swfdec_as_value_to_primitive (rval
);
1029 if (SWFDEC_AS_VALUE_IS_OBJECT (rval
) &&
1030 !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (rval
))) {
1031 swfdec_as_stack_pop (cx
);
1032 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
1035 /* movieclips are not objects, but they evaluate to NaN, so we can handle them here */
1036 if (SWFDEC_AS_VALUE_IS_OBJECT (rval
) ||
1037 SWFDEC_AS_VALUE_IS_OBJECT (lval
)) {
1038 swfdec_as_stack_pop (cx
);
1039 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1042 /* if both are strings, compare strings */
1043 if (SWFDEC_AS_VALUE_IS_STRING (rval
) &&
1044 SWFDEC_AS_VALUE_IS_STRING (lval
)) {
1045 const char *ls
= SWFDEC_AS_VALUE_GET_STRING (lval
);
1046 const char *rs
= SWFDEC_AS_VALUE_GET_STRING (rval
);
1048 if (ls
== SWFDEC_AS_STR_EMPTY
) {
1049 cmp
= rs
== SWFDEC_AS_STR_EMPTY
? 0 : 1;
1050 } else if (rs
== SWFDEC_AS_STR_EMPTY
) {
1053 cmp
= strcmp (ls
, rs
);
1055 swfdec_as_stack_pop (cx
);
1056 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cmp
< 0);
1059 /* convert to numbers and compare those */
1060 l
= swfdec_as_value_to_number (cx
, lval
);
1061 r
= swfdec_as_value_to_number (cx
, rval
);
1062 swfdec_as_stack_pop (cx
);
1063 /* NaN results in undefined */
1064 if (isnan (l
) || isnan (r
)) {
1065 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1068 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), l
< r
);
1072 swfdec_action_not (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1074 if (cx
->version
<= 4) {
1075 double d
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1076 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), d
== 0 ? 1 : 0);
1078 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1),
1079 !swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1)));
1084 swfdec_action_jump (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1087 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len
);
1090 cx
->frame
->pc
+= 5 + GINT16_FROM_LE (*((gint16
*) data
));
1094 swfdec_action_if (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1097 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len
);
1100 if (swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1)))
1101 cx
->frame
->pc
+= 5 + GINT16_FROM_LE (*((gint16
*) data
));
1102 swfdec_as_stack_pop (cx
);
1106 swfdec_action_decrement (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1110 val
= swfdec_as_stack_peek (cx
, 1);
1111 SWFDEC_AS_VALUE_SET_NUMBER (val
, swfdec_as_value_to_number (cx
, val
) - 1);
1115 swfdec_action_increment (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1119 val
= swfdec_as_stack_peek (cx
, 1);
1120 SWFDEC_AS_VALUE_SET_NUMBER (val
, swfdec_as_value_to_number (cx
, val
) + 1);
1124 swfdec_action_get_url (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1129 swfdec_bits_init_data (&bits
, data
, len
);
1130 url
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1131 target
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1132 if (url
== NULL
|| target
== NULL
) {
1133 SWFDEC_ERROR ("not enough data in GetURL");
1138 if (swfdec_bits_left (&bits
)) {
1139 SWFDEC_WARNING ("leftover bytes in GetURL action");
1141 if (!SWFDEC_IS_PLAYER (cx
)) {
1142 SWFDEC_ERROR ("GetURL without a SwfdecPlayer");
1143 } else if (swfdec_player_request_fscommand (SWFDEC_PLAYER (cx
), url
, target
)) {
1144 /* nothing to do here */
1145 } else if (swfdec_player_get_level (SWFDEC_PLAYER (cx
), target
) >= 0) {
1146 swfdec_resource_load (SWFDEC_PLAYER (cx
), target
, url
,
1147 SWFDEC_LOADER_REQUEST_DEFAULT
, NULL
, NULL
);
1154 swfdec_action_get_url2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1156 const char *target
, *url
;
1157 guint method
, internal
, variables
;
1160 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
1164 method
= data
[0] & 3;
1166 SWFDEC_ERROR ("GetURL method 3 invalid");
1169 internal
= data
[0] & 64;
1170 variables
= data
[0] & 128;
1171 if (method
== 1 || method
== 2) {
1172 SWFDEC_FIXME ("encode variables");
1175 target
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1176 url
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1178 if (!SWFDEC_IS_PLAYER (cx
)) {
1179 SWFDEC_ERROR ("GetURL2 action requires a SwfdecPlayer");
1180 } else if (swfdec_player_request_fscommand (SWFDEC_PLAYER (cx
), url
, target
)) {
1181 /* nothing to do here */
1182 } else if (variables
) {
1185 movie
= swfdec_player_get_movie_from_string (SWFDEC_PLAYER (cx
), target
);
1186 if (SWFDEC_IS_SPRITE_MOVIE (movie
)) {
1187 swfdec_movie_load_variables (movie
, url
, method
, NULL
);
1189 } else if (internal
) {
1190 swfdec_resource_load (SWFDEC_PLAYER (cx
), target
, url
, method
, NULL
, NULL
);
1192 /* load an external file */
1193 swfdec_player_launch (SWFDEC_PLAYER (cx
), method
, url
, target
, NULL
);
1196 swfdec_as_stack_pop_n (cx
, 2);
1200 swfdec_action_string_add (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1202 const char *lval
, *rval
;
1204 rval
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1205 lval
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1206 lval
= swfdec_as_str_concat (cx
, lval
, rval
);
1207 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 2), lval
);
1208 swfdec_as_stack_pop (cx
);
1212 swfdec_action_push_duplicate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1214 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
1216 *swfdec_as_stack_push (cx
) = *val
;
1220 swfdec_action_random_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1225 val
= swfdec_as_stack_peek (cx
, 1);
1226 max
= swfdec_as_value_to_integer (cx
, val
);
1229 SWFDEC_AS_VALUE_SET_NUMBER (val
, 0);
1231 SWFDEC_AS_VALUE_SET_NUMBER (val
, g_rand_int_range (cx
->rand
, 0, max
));
1235 swfdec_action_old_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1240 l
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
1241 r
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
1243 case SWFDEC_AS_ACTION_EQUALS
:
1246 case SWFDEC_AS_ACTION_LESS
:
1250 g_assert_not_reached ();
1253 swfdec_as_stack_pop (cx
);
1254 if (cx
->version
< 5) {
1255 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), cond
? 1 : 0);
1257 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1262 swfdec_action_string_extract (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1267 n
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1268 start
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1269 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 3));
1270 swfdec_as_stack_pop_n (cx
, 2);
1271 left
= g_utf8_strlen (s
, -1);
1273 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR_EMPTY
);
1275 } else if (start
< 2) {
1281 if (n
< 0 || n
> left
)
1284 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
1285 swfdec_as_str_sub (cx
, s
, start
, n
));
1289 swfdec_action_string_length (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1294 v
= swfdec_as_stack_peek (cx
, 1);
1295 s
= swfdec_as_value_to_string (cx
, v
);
1296 SWFDEC_AS_VALUE_SET_INT (v
, g_utf8_strlen (s
, -1));
1300 swfdec_action_string_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1305 r
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1306 l
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1308 case SWFDEC_AS_ACTION_STRING_EQUALS
:
1311 case SWFDEC_AS_ACTION_STRING_LESS
:
1312 cond
= strcmp (l
, r
) < 0;
1315 g_assert_not_reached ();
1318 swfdec_as_stack_pop (cx
);
1319 if (cx
->version
< 5) {
1320 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), cond
? 1 : 0);
1322 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1327 swfdec_action_equals2_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1329 SwfdecAsValue
*rval
, *lval
;
1330 SwfdecAsValue rtmp
, ltmp
;
1331 SwfdecAsValueType ltype
, rtype
;
1335 rval
= swfdec_as_stack_peek (cx
, 1);
1336 lval
= swfdec_as_stack_peek (cx
, 2);
1339 swfdec_as_value_to_primitive (&rtmp
);
1340 swfdec_as_value_to_primitive (<mp
);
1344 /* get objects compared */
1345 if (ltype
== SWFDEC_AS_TYPE_OBJECT
&& rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1346 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (<mp
);
1347 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
);
1349 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1350 lo
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (lo
)));
1351 ro
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (ro
)));
1352 } else if (SWFDEC_IS_MOVIE (lo
)) {
1353 swfdec_as_value_to_primitive (rval
);
1355 if (rtype
!= SWFDEC_AS_TYPE_OBJECT
) {
1359 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1360 } else if (SWFDEC_IS_MOVIE (ro
)) {
1361 swfdec_as_value_to_primitive (lval
);
1363 if (ltype
!= SWFDEC_AS_TYPE_OBJECT
) {
1367 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1369 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1370 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1376 /* compare strings */
1377 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1378 /* FIXME: flash 5 case insensitive? */
1379 cond
= SWFDEC_AS_VALUE_GET_STRING (<mp
) == SWFDEC_AS_VALUE_GET_STRING (&rtmp
);
1383 /* convert to numbers */
1384 if (SWFDEC_AS_VALUE_IS_OBJECT (<mp
) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (<mp
))) {
1385 l
= swfdec_as_value_to_number (cx
, lval
);
1387 l
= swfdec_as_value_to_number (cx
, <mp
);
1389 if (SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (&rtmp
))) {
1390 r
= swfdec_as_value_to_number (cx
, rval
);
1392 r
= swfdec_as_value_to_number (cx
, &rtmp
);
1395 /* get rid of undefined and null */
1396 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1397 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1404 /* else compare as numbers */
1405 if (isnan (l
) && isnan (r
))
1406 cond
= ltype
== rtype
;
1411 swfdec_as_stack_pop (cx
);
1412 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1416 swfdec_action_equals2_6 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1418 SwfdecAsValue
*rval
, *lval
;
1419 SwfdecAsValueType ltype
, rtype
;
1423 rval
= swfdec_as_stack_peek (cx
, 1);
1424 lval
= swfdec_as_stack_peek (cx
, 2);
1428 /* get objects compared */
1429 if (ltype
== SWFDEC_AS_TYPE_OBJECT
&& rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1430 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1431 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1433 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1434 lo
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (lo
)));
1435 ro
= SWFDEC_AS_OBJECT (swfdec_movie_resolve (SWFDEC_MOVIE (ro
)));
1436 } else if (SWFDEC_IS_MOVIE (lo
)) {
1437 swfdec_as_value_to_primitive (rval
);
1439 if (rtype
!= SWFDEC_AS_TYPE_OBJECT
) {
1443 ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1444 } else if (SWFDEC_IS_MOVIE (ro
)) {
1445 swfdec_as_value_to_primitive (lval
);
1447 if (ltype
!= SWFDEC_AS_TYPE_OBJECT
) {
1451 lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1457 /* if one of the values is an object, call valueOf.
1458 * If it's still an object, return FALSE */
1459 swfdec_as_value_to_primitive (lval
);
1461 if (ltype
== SWFDEC_AS_TYPE_OBJECT
) {
1465 swfdec_as_value_to_primitive (rval
);
1467 if (rtype
== SWFDEC_AS_TYPE_OBJECT
) {
1471 /* now we have a comparison without objects */
1473 /* get rid of undefined and null */
1474 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1475 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1482 /* compare strings */
1483 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1484 /* FIXME: flash 5 case insensitive? */
1485 cond
= SWFDEC_AS_VALUE_GET_STRING (lval
) == SWFDEC_AS_VALUE_GET_STRING (rval
);
1489 /* else compare as numbers */
1490 l
= swfdec_as_value_to_number (cx
, lval
);
1491 r
= swfdec_as_value_to_number (cx
, rval
);
1493 if (isnan (l
) && isnan (r
))
1494 cond
= ltype
== rtype
;
1499 swfdec_as_stack_pop (cx
);
1500 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1504 swfdec_action_equals2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1506 if (cx
->version
<= 5) {
1507 swfdec_action_equals2_5 (cx
, action
, data
, len
);
1509 swfdec_action_equals2_6 (cx
, action
, data
, len
);
1514 swfdec_action_strict_equals (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1516 SwfdecAsValue
*rval
, *lval
;
1519 rval
= swfdec_as_stack_peek (cx
, 1);
1520 lval
= swfdec_as_stack_peek (cx
, 2);
1522 if (rval
->type
!= lval
->type
) {
1525 switch (rval
->type
) {
1526 case SWFDEC_AS_TYPE_UNDEFINED
:
1527 case SWFDEC_AS_TYPE_NULL
:
1530 case SWFDEC_AS_TYPE_BOOLEAN
:
1531 cond
= SWFDEC_AS_VALUE_GET_BOOLEAN (rval
) == SWFDEC_AS_VALUE_GET_BOOLEAN (lval
);
1533 case SWFDEC_AS_TYPE_NUMBER
:
1536 r
= SWFDEC_AS_VALUE_GET_NUMBER (rval
);
1537 l
= SWFDEC_AS_VALUE_GET_NUMBER (lval
);
1538 cond
= (l
== r
) || (isnan (l
) && isnan (r
));
1541 case SWFDEC_AS_TYPE_STRING
:
1542 cond
= SWFDEC_AS_VALUE_GET_STRING (rval
) == SWFDEC_AS_VALUE_GET_STRING (lval
);
1544 case SWFDEC_AS_TYPE_OBJECT
:
1546 SwfdecAsObject
*lo
= SWFDEC_AS_VALUE_GET_OBJECT (lval
);
1547 SwfdecAsObject
*ro
= SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1548 if (SWFDEC_IS_MOVIE (lo
) && SWFDEC_IS_MOVIE (ro
)) {
1549 cond
= swfdec_movie_resolve (SWFDEC_MOVIE (lo
)) == swfdec_movie_resolve (SWFDEC_MOVIE (ro
));
1550 } else if (!SWFDEC_IS_MOVIE (lo
) && !SWFDEC_IS_MOVIE (ro
)) {
1557 case SWFDEC_AS_TYPE_INT
:
1559 g_assert_not_reached ();
1564 swfdec_as_stack_pop (cx
);
1565 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1569 swfdec_action_do_set_target (SwfdecAsContext
*cx
, const char *target
, const char *end
)
1571 swfdec_as_frame_set_target (cx
->frame
, NULL
);
1573 if (target
!= end
) {
1574 SwfdecAsObject
*o
= swfdec_action_lookup_object (cx
, NULL
, target
, end
);
1576 SWFDEC_WARNING ("target \"%s\" is not an object", target
);
1577 } else if (!SWFDEC_IS_MOVIE (o
)) {
1578 SWFDEC_FIXME ("target \"%s\" is not a movie, something weird is supposed to happen now", target
);
1581 swfdec_as_frame_set_target (cx
->frame
, o
);
1586 swfdec_action_set_target (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1590 end
= memchr (data
, 0, len
);
1592 SWFDEC_ERROR ("SetTarget action does not specify a string");
1595 swfdec_action_do_set_target (cx
, (const char *) data
, end
);
1599 swfdec_action_set_target2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1603 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1604 swfdec_action_do_set_target (cx
, s
, s
+ strlen (s
));
1605 swfdec_as_stack_pop (cx
);
1609 swfdec_action_start_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1611 SwfdecRect rect
, *rectp
= NULL
;
1614 guint stack_size
= 3;
1616 swfdec_as_stack_ensure_size (cx
, 3);
1617 center
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
1618 if (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 3))) {
1619 swfdec_as_stack_ensure_size (cx
, 7);
1620 rect
.x0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 7));
1621 rect
.y0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 6));
1622 rect
.x1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 5));
1623 rect
.y1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 4));
1624 swfdec_rect_scale (&rect
, &rect
, SWFDEC_TWIPS_SCALE_FACTOR
);
1628 if (!SWFDEC_IS_PLAYER (cx
)) {
1629 SWFDEC_ERROR ("called startDrag on a non-SwfdecPlayer");
1631 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
), swfdec_as_stack_peek (cx
, 1));
1632 if (movie
!= NULL
) {
1633 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), movie
, center
, rectp
);
1635 SWFDEC_ERROR ("startDrag on something not a Movie");
1638 swfdec_as_stack_pop_n (cx
, stack_size
);
1642 swfdec_action_end_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1644 if (SWFDEC_IS_PLAYER (cx
)) {
1645 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), NULL
, FALSE
, NULL
);
1647 SWFDEC_WARNING ("can't end a drag on non-players");
1652 swfdec_action_stop_sounds (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1654 if (SWFDEC_IS_PLAYER (cx
)) {
1655 swfdec_player_stop_all_sounds (SWFDEC_PLAYER (cx
));
1660 swfdec_action_new_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1662 SwfdecAsValue
*constructor
;
1663 SwfdecAsFunction
*fun
;
1666 swfdec_as_stack_ensure_size (cx
, 2);
1667 swfdec_action_get_variable (cx
, action
, data
, len
);
1668 constructor
= swfdec_as_stack_peek (cx
, 1);
1669 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1670 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 2, n_args
);
1671 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1672 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
))) {
1673 SWFDEC_WARNING ("not a constructor");
1677 swfdec_as_stack_pop_n (cx
, 2);
1678 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1682 swfdec_as_stack_pop_n (cx
, n_args
+ 1);
1683 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1687 swfdec_action_new_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1689 SwfdecAsValue
*constructor
;
1690 SwfdecAsFunction
*fun
;
1694 swfdec_as_stack_ensure_size (cx
, 3);
1695 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1697 constructor
= swfdec_as_stack_peek (cx
, 2);
1698 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
1699 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 3, n_args
);
1700 if (name
!= SWFDEC_AS_STR_EMPTY
) {
1701 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
)) {
1702 SWFDEC_WARNING ("NewMethod called without an object to get variable %s from", name
);
1705 swfdec_as_object_get_variable (SWFDEC_AS_VALUE_GET_OBJECT (constructor
),
1708 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1709 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
))) {
1710 SWFDEC_WARNING ("%s is not a constructor", name
);
1714 swfdec_as_stack_pop_n (cx
, 3);
1715 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1719 swfdec_as_stack_pop_n (cx
, n_args
+ 2);
1720 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1724 swfdec_action_init_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1726 SwfdecAsObject
*object
;
1727 guint i
, n_args
, size
;
1729 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1730 swfdec_as_stack_pop (cx
);
1731 if (n_args
* 2 > swfdec_as_stack_get_size (cx
)) {
1732 size
= swfdec_as_stack_get_size (cx
);
1733 SWFDEC_FIXME ("InitObject action with too small stack, help!");
1740 object
= swfdec_as_object_new (cx
);
1743 for (i
= 0; i
< n_args
; i
++) {
1744 const char *s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1745 swfdec_as_object_set_variable (object
, s
, swfdec_as_stack_peek (cx
, 1));
1746 swfdec_as_stack_pop_n (cx
, 2);
1748 swfdec_as_stack_pop_n (cx
, size
);
1749 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
1753 swfdec_action_init_array (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1756 SwfdecAsObject
*array
;
1758 swfdec_as_stack_ensure_size (cx
, 1);
1759 n
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1760 swfdec_as_stack_pop (cx
);
1761 array
= swfdec_as_array_new (cx
);
1764 /* NB: we can't increase the stack here, as the number can easily be MAXINT */
1765 for (i
= 0; i
< n
&& swfdec_as_stack_get_size (cx
) > 0; i
++) {
1766 swfdec_as_stack_ensure_size (cx
, 1);
1767 swfdec_as_array_push (SWFDEC_AS_ARRAY (array
), swfdec_as_stack_pop (cx
));
1771 SWFDEC_AS_VALUE_SET_INT (&val
, i
);
1772 swfdec_as_object_set_variable (array
, SWFDEC_AS_STR_length
, &val
);
1774 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), array
);
1778 swfdec_action_define_function (SwfdecAsContext
*cx
, guint action
,
1779 const guint8
*data
, guint len
)
1781 char *function_name
;
1782 const char *name
= NULL
;
1783 guint i
, n_args
, size
, n_registers
;
1785 SwfdecBuffer
*buffer
;
1786 SwfdecAsFunction
*fun
;
1787 SwfdecAsFrame
*frame
;
1788 SwfdecScript
*script
;
1790 SwfdecScriptArgument
*args
;
1791 gboolean v2
= (action
== 0x8e);
1794 swfdec_bits_init_data (&bits
, data
, len
);
1795 function_name
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1796 if (function_name
== NULL
) {
1797 SWFDEC_ERROR ("could not parse function name");
1800 n_args
= swfdec_bits_get_u16 (&bits
);
1802 n_registers
= swfdec_bits_get_u8 (&bits
);
1803 if (n_registers
== 0)
1805 flags
= swfdec_bits_get_u16 (&bits
);
1810 args
= g_new0 (SwfdecScriptArgument
, n_args
);
1811 for (i
= 0; i
< n_args
&& swfdec_bits_left (&bits
); i
++) {
1813 args
[i
].preload
= swfdec_bits_get_u8 (&bits
);
1814 if (args
[i
].preload
&& args
[i
].preload
>= n_registers
) {
1815 SWFDEC_ERROR ("argument %u cannot be preloaded into register %u out of %u",
1816 i
, args
[i
].preload
, n_registers
);
1817 /* FIXME: figure out correct error handling here */
1818 args
[i
].preload
= 0;
1821 args
[i
].name
= swfdec_bits_get_string_with_version (&bits
, cx
->version
);
1822 if (args
[i
].name
== NULL
|| args
[i
].name
== '\0') {
1823 SWFDEC_ERROR ("empty argument name not allowed");
1827 /* FIXME: check duplicate arguments */
1832 size
= swfdec_bits_get_u16 (&bits
);
1833 /* check the script can be created */
1834 if (frame
->script
->buffer
->data
+ frame
->script
->buffer
->length
< frame
->pc
+ 3 + len
+ size
) {
1835 SWFDEC_ERROR ("size of function is too big");
1837 g_free (function_name
);
1840 /* create the script */
1841 buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
1842 frame
->pc
+ 3 + len
- frame
->script
->buffer
->data
, size
);
1843 swfdec_bits_init (&bits
, buffer
);
1844 if (*function_name
) {
1845 name
= function_name
;
1846 } else if (swfdec_as_stack_get_size (cx
) > 0) {
1847 /* This is kind of a hack that uses a feature of the Adobe compiler:
1848 * foo = function () {} is compiled as these actions:
1849 * Push "foo", DefineFunction, SetVariable/SetMember
1850 * With this knowledge we can inspect the topmost stack member, since
1851 * it will contain the name this function will soon be assigned to.
1853 if (SWFDEC_AS_VALUE_IS_STRING (swfdec_as_stack_peek (cx
, 1)))
1854 name
= SWFDEC_AS_VALUE_GET_STRING (swfdec_as_stack_peek (cx
, 1));
1857 name
= "unnamed_function";
1858 script
= swfdec_script_new_from_bits (&bits
, name
, cx
->version
);
1859 swfdec_buffer_unref (buffer
);
1860 if (script
== NULL
) {
1861 SWFDEC_ERROR ("failed to create script");
1863 g_free (function_name
);
1866 if (frame
->constant_pool_buffer
)
1867 script
->constant_pool
= swfdec_buffer_ref (frame
->constant_pool_buffer
);
1868 script
->flags
= flags
;
1869 script
->n_registers
= n_registers
;
1870 script
->n_arguments
= n_args
;
1871 script
->arguments
= args
;
1872 /* see function-scope tests */
1873 if (cx
->version
> 5) {
1874 /* FIXME: or original target? */
1875 fun
= swfdec_as_script_function_new (frame
->original_target
, frame
->scope_chain
, script
);
1877 fun
= swfdec_as_script_function_new (frame
->original_target
, NULL
, script
);
1881 /* This is a hack that should only trigger for functions defined in the init scripts.
1882 * It is supposed to ensure that those functions inherit their target when being
1883 * called instead of when being defined */
1884 if (!SWFDEC_IS_MOVIE (frame
->original_target
))
1885 SWFDEC_AS_SCRIPT_FUNCTION (fun
)->target
= NULL
;
1886 /* attach the function */
1887 if (*function_name
== '\0') {
1888 swfdec_as_stack_ensure_free (cx
, 1);
1889 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), SWFDEC_AS_OBJECT (fun
));
1891 SwfdecAsValue funval
;
1892 /* FIXME: really varobj? Not eval or sth like that? */
1893 name
= swfdec_as_context_get_string (cx
, function_name
);
1894 SWFDEC_AS_VALUE_SET_OBJECT (&funval
, SWFDEC_AS_OBJECT (fun
));
1895 swfdec_as_object_set_variable (frame
->target
, name
, &funval
);
1898 /* update current context */
1899 frame
->pc
+= 3 + len
+ size
;
1900 g_free (function_name
);
1904 swfdec_action_bitwise (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1908 a
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1909 b
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1922 g_assert_not_reached ();
1926 swfdec_as_stack_pop (cx
);
1927 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_peek (cx
, 1), a
);
1931 swfdec_action_shift (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1935 amount
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1937 value
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1941 value
= value
<< amount
;
1944 value
= ((gint
) value
) >> amount
;
1947 value
= ((guint
) value
) >> amount
;
1950 g_assert_not_reached ();
1953 swfdec_as_stack_pop (cx
);
1954 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_peek (cx
, 1), value
);
1958 swfdec_action_to_integer (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1960 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
1962 SWFDEC_AS_VALUE_SET_INT (val
, swfdec_as_value_to_integer (cx
, val
));
1966 swfdec_action_target_path (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1972 val
= swfdec_as_stack_peek (cx
, 1);
1974 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
) ||
1975 !SWFDEC_IS_MOVIE (movie
= (SwfdecMovie
*) SWFDEC_AS_VALUE_GET_OBJECT (val
))) {
1976 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
1979 s
= swfdec_movie_get_path (movie
, TRUE
);
1980 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_give_string (cx
, s
));
1984 swfdec_action_define_local (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1986 SwfdecAsObject
*target
;
1989 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1990 if (cx
->frame
->is_local
) {
1991 target
= SWFDEC_AS_OBJECT (cx
->frame
);
1993 target
= cx
->frame
->target
;
1995 swfdec_as_object_set_variable (target
, name
,
1996 swfdec_as_stack_peek (cx
, 1));
1997 swfdec_as_stack_pop_n (cx
, 2);
2001 swfdec_action_define_local2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2003 SwfdecAsValue val
= { 0, };
2004 SwfdecAsObject
*target
;
2007 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
2008 if (cx
->frame
->is_local
) {
2009 target
= SWFDEC_AS_OBJECT (cx
->frame
);
2011 target
= cx
->frame
->target
;
2013 swfdec_as_object_set_variable (target
, name
, &val
);
2014 swfdec_as_stack_pop (cx
);
2018 swfdec_action_return (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2020 swfdec_as_frame_return (cx
->frame
, swfdec_as_stack_pop (cx
));
2024 swfdec_action_delete (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2028 gboolean success
= FALSE
;
2030 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
2031 val
= swfdec_as_stack_peek (cx
, 2);
2032 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2033 success
= swfdec_as_object_delete_variable (
2034 SWFDEC_AS_VALUE_GET_OBJECT (val
), name
) == SWFDEC_AS_DELETE_DELETED
;
2036 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
2037 swfdec_as_stack_pop_n (cx
, 1);
2041 swfdec_action_delete2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2045 gboolean success
= FALSE
;
2047 val
= swfdec_as_stack_peek (cx
, 1);
2048 name
= swfdec_as_value_to_string (cx
, val
);
2049 success
= swfdec_as_frame_delete_variable (cx
->frame
, name
) == SWFDEC_AS_DELETE_DELETED
;
2050 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
2054 swfdec_action_store_register (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2057 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
2060 if (!swfdec_action_has_register (cx
, *data
)) {
2061 SWFDEC_ERROR ("Cannot store into register %u, not enough registers", (guint
) *data
);
2064 cx
->frame
->registers
[*data
] = *swfdec_as_stack_peek (cx
, 1);
2068 swfdec_action_modulo (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2072 y
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
2073 x
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
2074 /* yay, we're portable! */
2081 SWFDEC_FIXME ("errno set after fmod");
2084 swfdec_as_stack_pop (cx
);
2085 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1), x
);
2089 swfdec_action_swap (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2091 swfdec_as_stack_swap (cx
, 1, 2);
2095 swfdec_action_to_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2097 SWFDEC_AS_VALUE_SET_NUMBER (swfdec_as_stack_peek (cx
, 1),
2098 swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)));
2102 swfdec_action_to_string (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2104 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
2105 swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1)));
2109 swfdec_action_type_of (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2114 val
= swfdec_as_stack_peek (cx
, 1);
2115 switch (val
->type
) {
2116 case SWFDEC_AS_TYPE_NUMBER
:
2117 type
= SWFDEC_AS_STR_number
;
2119 case SWFDEC_AS_TYPE_BOOLEAN
:
2120 type
= SWFDEC_AS_STR_boolean
;
2122 case SWFDEC_AS_TYPE_STRING
:
2123 type
= SWFDEC_AS_STR_string
;
2125 case SWFDEC_AS_TYPE_UNDEFINED
:
2126 type
= SWFDEC_AS_STR_undefined
;
2128 case SWFDEC_AS_TYPE_NULL
:
2129 type
= SWFDEC_AS_STR_null
;
2131 case SWFDEC_AS_TYPE_OBJECT
:
2133 SwfdecAsObject
*obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2134 if (SWFDEC_IS_MOVIE (obj
)) {
2135 if (SWFDEC_IS_TEXT_FIELD_MOVIE (obj
)) {
2136 type
= SWFDEC_AS_STR_object
;
2138 type
= SWFDEC_AS_STR_movieclip
;
2140 } else if (SWFDEC_IS_AS_FUNCTION (obj
)) {
2141 type
= SWFDEC_AS_STR_function
;
2143 type
= SWFDEC_AS_STR_object
;
2147 case SWFDEC_AS_TYPE_INT
:
2149 g_assert_not_reached ();
2150 type
= SWFDEC_AS_STR_EMPTY
;
2153 SWFDEC_AS_VALUE_SET_STRING (val
, type
);
2157 swfdec_action_get_time (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2162 swfdec_as_context_get_time (cx
, &tv
);
2163 /* we assume here that swfdec_as_context_get_time always returns a tv > start_time */
2164 diff
= tv
.tv_sec
- cx
->start_time
.tv_sec
;
2165 if (diff
> G_MAXULONG
/ 1000 - 1) {
2166 SWFDEC_ERROR ("FIXME: time overflow");
2169 diff
= diff
+ (tv
.tv_usec
- cx
->start_time
.tv_usec
) / 1000;
2171 SWFDEC_AS_VALUE_SET_INT (swfdec_as_stack_push (cx
), diff
);
2175 swfdec_action_is_instance_of (SwfdecAsObject
*object
,
2176 SwfdecAsObject
*constructor
)
2179 SwfdecAsObject
*class, *prototype
;
2182 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (object
), FALSE
);
2183 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (constructor
), FALSE
);
2185 // FIXME: propflag tests are wrong, and we shouldn't get __proto__.prototype
2186 swfdec_as_object_get_variable (constructor
, SWFDEC_AS_STR_prototype
, &val
);
2187 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
2189 prototype
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
2192 while ((class = swfdec_as_object_get_prototype (class)) != NULL
) {
2193 if (class == prototype
)
2195 for (iter
= class->interfaces
; iter
!= NULL
; iter
= iter
->next
) {
2196 if (iter
->data
== prototype
)
2205 swfdec_action_instance_of (SwfdecAsContext
*cx
, guint action
,
2206 const guint8
*data
, guint len
)
2209 SwfdecAsObject
*object
, *constructor
;
2211 val
= swfdec_as_stack_pop (cx
);
2212 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2213 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2218 val
= swfdec_as_stack_pop (cx
);
2219 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2220 object
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2226 if (object
== NULL
|| constructor
== NULL
) {
2227 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
), FALSE
);
2231 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
2232 swfdec_action_is_instance_of (object
, constructor
));
2236 swfdec_action_cast (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2240 SwfdecAsObject
*object
, *constructor
;
2242 val
= swfdec_as_stack_pop (cx
);
2243 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2244 object
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2249 val
= swfdec_as_stack_pop (cx
);
2250 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2251 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2256 if (object
== NULL
|| constructor
== NULL
) {
2257 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2261 if (swfdec_action_is_instance_of (object
, constructor
)) {
2262 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
2264 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2269 swfdec_action_implements (SwfdecAsContext
*cx
, guint action
,
2270 const guint8
*data
, guint len
)
2272 SwfdecAsValue
*val
, *argv
;
2273 SwfdecAsObject
*object
, *proto
, *interface
;
2276 swfdec_as_stack_ensure_size (cx
, 2);
2278 val
= swfdec_as_stack_pop (cx
);
2279 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2280 object
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2281 swfdec_as_object_get_variable (object
, SWFDEC_AS_STR_prototype
, val
);
2282 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2283 proto
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2292 val
= swfdec_as_stack_pop (cx
);
2293 argc
= swfdec_as_value_to_integer (cx
, val
);
2296 swfdec_as_stack_ensure_size (cx
, argc
);
2297 argv
= swfdec_as_stack_pop_n (cx
, argc
);
2305 for (i
= 0; i
< argc
; i
++) {
2306 if (!SWFDEC_AS_VALUE_IS_OBJECT (&argv
[i
]))
2308 interface
= SWFDEC_AS_VALUE_GET_OBJECT (&argv
[i
]);
2309 swfdec_as_object_get_variable (interface
, SWFDEC_AS_STR_prototype
, val
);
2310 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
))
2313 g_slist_prepend (proto
->interfaces
, SWFDEC_AS_VALUE_GET_OBJECT (val
));
2318 swfdec_action_extends (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2320 SwfdecAsValue
*superclass
, *subclass
, proto
;
2321 SwfdecAsObject
*prototype
;
2322 SwfdecAsObject
*super
;
2324 superclass
= swfdec_as_stack_peek (cx
, 1);
2325 subclass
= swfdec_as_stack_peek (cx
, 2);
2326 if (!SWFDEC_AS_VALUE_IS_OBJECT (superclass
) ||
2327 !SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (superclass
))) {
2328 SWFDEC_ERROR ("superclass is not a function");
2331 if (!SWFDEC_AS_VALUE_IS_OBJECT (subclass
)) {
2332 SWFDEC_ERROR ("subclass is not an object");
2335 super
= SWFDEC_AS_VALUE_GET_OBJECT (superclass
);
2336 prototype
= swfdec_as_object_new_empty (cx
);
2337 if (prototype
== NULL
)
2339 swfdec_as_object_get_variable (super
, SWFDEC_AS_STR_prototype
, &proto
);
2340 swfdec_as_object_set_variable (prototype
, SWFDEC_AS_STR___proto__
, &proto
);
2341 if (cx
->version
> 5) {
2342 swfdec_as_object_set_variable_and_flags (prototype
, SWFDEC_AS_STR___constructor__
,
2343 superclass
, SWFDEC_AS_VARIABLE_HIDDEN
);
2345 SWFDEC_AS_VALUE_SET_OBJECT (&proto
, prototype
);
2346 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_OBJECT (subclass
),
2347 SWFDEC_AS_STR_prototype
, &proto
);
2349 swfdec_as_stack_pop_n (cx
, 2);
2353 swfdec_action_enumerate_foreach (SwfdecAsObject
*object
, const char *variable
,
2354 SwfdecAsValue
*value
, guint flags
, gpointer listp
)
2356 GSList
**list
= listp
;
2358 if (flags
& SWFDEC_AS_VARIABLE_HIDDEN
)
2361 *list
= g_slist_remove (*list
, variable
);
2362 *list
= g_slist_prepend (*list
, (gpointer
) variable
);
2367 swfdec_action_do_enumerate (SwfdecAsContext
*cx
, SwfdecAsObject
*object
)
2370 GSList
*walk
, *list
= NULL
;
2372 for (i
= 0; i
< 256 && object
; i
++) {
2373 swfdec_as_object_foreach (object
, swfdec_action_enumerate_foreach
, &list
);
2374 object
= swfdec_as_object_get_prototype (object
);
2377 swfdec_as_context_abort (object
->context
, "Prototype recursion limit exceeded");
2378 g_slist_free (list
);
2381 list
= g_slist_reverse (list
);
2383 for (walk
= list
; walk
; walk
= walk
->next
) {
2384 /* 8 is an arbitrary value */
2386 swfdec_as_stack_ensure_free (cx
, 8);
2390 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
), walk
->data
);
2392 g_slist_free (list
);
2396 swfdec_action_enumerate2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2399 SwfdecAsObject
*obj
;
2401 val
= swfdec_as_stack_peek (cx
, 1);
2402 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2403 SWFDEC_WARNING ("Enumerate called without an object");
2404 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2407 obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2408 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2409 swfdec_action_do_enumerate (cx
, obj
);
2413 swfdec_action_enumerate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2415 /* FIXME: make this proper functions */
2416 swfdec_action_get_variable (cx
, action
, data
, len
);
2417 swfdec_action_enumerate2 (cx
, action
, data
, len
);
2421 swfdec_action_logical (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2425 if (cx
->version
<= 4) {
2426 l
= (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)) != 0);
2427 // don't call second parameter if not necessary
2428 if ((action
== SWFDEC_AS_ACTION_AND
&& !l
) ||
2429 (action
!= SWFDEC_AS_ACTION_AND
&& l
)) {
2430 r
= (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2)) != 0);
2435 l
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1));
2436 r
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
2439 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 2),
2440 (action
== SWFDEC_AS_ACTION_AND
) ? (l
&& r
) : (l
|| r
));
2441 swfdec_as_stack_pop (cx
);
2445 swfdec_action_char_to_ascii (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2447 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2448 const char *s
= swfdec_as_value_to_string (cx
, val
);
2450 if (cx
->version
<= 5) {
2451 char *ascii
= g_convert (s
, -1, "LATIN1", "UTF-8", NULL
, NULL
, NULL
);
2453 if (ascii
== NULL
) {
2454 /* This can happen if a Flash 5 movie gets loaded into a Flash 7 movie */
2455 SWFDEC_FIXME ("Someone threw unconvertible text %s at Flash <= 5", s
);
2456 SWFDEC_AS_VALUE_SET_INT (val
, 0); /* FIXME: what to return??? */
2458 SWFDEC_AS_VALUE_SET_INT (val
, (guchar
) ascii
[0]);
2462 gunichar
*uni
= g_utf8_to_ucs4_fast (s
, -1, NULL
);
2465 /* This should never happen, everything is valid UTF-8 in here */
2466 g_warning ("conversion of character %s failed", s
);
2467 SWFDEC_AS_VALUE_SET_INT (val
, 0);
2469 SWFDEC_AS_VALUE_SET_INT (val
, uni
[0]);
2476 swfdec_action_ascii_to_char (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2478 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2480 if (cx
->version
<= 5) {
2485 if (action
== SWFDEC_AS_ACTION_ASCII_TO_CHAR
) {
2486 s
[0] = ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 256;
2489 g_assert (action
== SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
);
2491 i
= ((guint
) swfdec_as_value_to_integer (cx
, val
));
2502 utf8
= g_convert (s
, -1, "UTF-8", "LATIN1", NULL
, NULL
, NULL
);
2504 g_warning ("conversion of character %u failed", (guint
) s
[0]);
2505 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2507 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, utf8
));
2512 gunichar c
= ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 65536;
2514 s
= g_ucs4_to_utf8 (&c
, 1, NULL
, NULL
, NULL
);
2516 g_warning ("conversion of character %u failed", (guint
) c
);
2517 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2519 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, s
));
2526 swfdec_action_throw (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2529 swfdec_as_context_throw (cx
, swfdec_as_stack_pop (cx
));
2533 const guint8
* catch_start
;
2534 const guint8
* finally_start
;
2538 gboolean use_register
;
2540 guint register_number
;
2541 char * variable_name
;
2546 swfdec_action_try_data_free (gpointer data
)
2548 TryData
*try_data
= data
;
2550 g_return_if_fail (try_data
!= NULL
);
2552 if (!try_data
->use_register
)
2553 g_free (try_data
->variable_name
);
2558 swfdec_action_try_end_finally (SwfdecAsFrame
*frame
, gpointer data
)
2560 SwfdecAsValue
*exception_value
= data
;
2561 SwfdecAsContext
*cx
;
2563 g_return_if_fail (SWFDEC_IS_AS_FRAME (frame
));
2564 g_return_if_fail (SWFDEC_IS_AS_VALUE (exception_value
));
2566 cx
= SWFDEC_AS_OBJECT (frame
)->context
;
2568 // finally has ended and we had exception stored, throw it
2570 swfdec_as_context_throw (cx
, exception_value
);
2576 swfdec_action_try_end_catch (SwfdecAsFrame
*frame
, gpointer data
)
2578 TryData
*try_data
= data
;
2579 SwfdecAsContext
*cx
;
2580 SwfdecAsValue
*exception_value
, val
;
2582 g_return_if_fail (SWFDEC_IS_AS_FRAME (frame
));
2583 g_return_if_fail (try_data
!= NULL
);
2585 cx
= SWFDEC_AS_OBJECT (frame
)->context
;
2587 if (swfdec_as_context_catch (cx
, &val
))
2589 // we got an exception while in catch block:
2590 // create new block for finally to pass on the exception
2591 // jump to that block
2593 exception_value
= g_malloc (sizeof (SwfdecAsValue
));
2594 *exception_value
= val
;
2596 // FIXME: the exception value is not marked while finally block runs
2597 swfdec_as_frame_push_block (frame
, try_data
->finally_start
,
2598 try_data
->finally_start
+ try_data
->finally_size
,
2599 swfdec_action_try_end_finally
, exception_value
);
2600 frame
->pc
= try_data
->finally_start
;
2603 swfdec_action_try_data_free (try_data
);
2607 swfdec_action_try_end_try (SwfdecAsFrame
*frame
, gpointer data
)
2609 TryData
*try_data
= data
;
2610 SwfdecAsContext
*cx
;
2613 g_return_if_fail (SWFDEC_IS_AS_FRAME (frame
));
2614 g_return_if_fail (try_data
!= NULL
);
2616 // if we don't have a catch block, we handle try block exactly like it was
2618 if (!try_data
->catch_start
) {
2619 swfdec_action_try_end_catch (frame
, try_data
);
2623 cx
= SWFDEC_AS_OBJECT (frame
)->context
;
2625 if (swfdec_as_context_catch (cx
, &val
))
2627 // we got an exception while in try block:
2628 // set the exception variable
2629 // add new block for catch and jump to it
2631 if (try_data
->use_register
)
2633 if (swfdec_action_has_register (cx
, try_data
->register_number
)) {
2634 cx
->frame
->registers
[try_data
->register_number
] = val
;
2636 SWFDEC_ERROR ("cannot set Error to register %u: not enough registers",
2637 try_data
->register_number
);
2642 // FIXME: this is duplicate of SetVariable
2643 SwfdecAsObject
*object
;
2644 const char *s
, *rest
;
2646 s
= swfdec_as_context_get_string (cx
, try_data
->variable_name
);
2647 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &rest
)) {
2648 if (object
&& rest
) {
2649 swfdec_as_object_set_variable (object
,
2650 swfdec_as_context_get_string (cx
, rest
), &val
);
2655 rest
= swfdec_as_context_get_string (cx
, rest
);
2657 swfdec_as_frame_set_variable (frame
, rest
, &val
);
2662 SWFDEC_ERROR ("cannot set Error to variable %s",
2663 try_data
->variable_name
);
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
;
2674 swfdec_action_try_data_free (try_data
);
2679 swfdec_action_try (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2684 gboolean use_finally
, use_catch
;
2687 SWFDEC_ERROR ("With action requires a length of at least 8, but got %u",
2692 try_data
= g_malloc0 (sizeof (TryData
));
2694 swfdec_bits_init_data (&bits
, data
, len
);
2696 swfdec_bits_getbits (&bits
, 5); // reserved
2697 try_data
->use_register
= swfdec_bits_getbit (&bits
);
2698 use_finally
= swfdec_bits_getbit (&bits
);
2699 use_catch
= swfdec_bits_getbit (&bits
);
2701 try_size
= swfdec_bits_get_u16 (&bits
);
2702 try_data
->catch_size
= swfdec_bits_get_u16 (&bits
);
2703 try_data
->finally_size
= swfdec_bits_get_u16 (&bits
);
2705 try_data
->catch_start
= data
+ len
+ try_size
;
2707 try_data
->finally_start
= try_data
->catch_start
+ try_data
->catch_size
;
2709 if (try_data
->use_register
) {
2710 try_data
->register_number
= swfdec_bits_get_u8 (&bits
);
2712 try_data
->variable_name
=
2713 swfdec_bits_get_string_with_version (&bits
, cx
->version
);
2716 if (swfdec_bits_left (&bits
)) {
2717 SWFDEC_WARNING ("leftover bytes in Try action");
2720 if (try_data
->catch_start
|| try_data
->finally_start
) {
2721 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ try_size
,
2722 swfdec_action_try_end_try
, try_data
);
2724 SWFDEC_WARNING ("Try with neither catch nor finally block");
2725 swfdec_action_try_data_free (try_data
);
2730 swfdec_action_pop_with (SwfdecAsFrame
*frame
, gpointer with_object
)
2732 g_assert (frame
->scope_chain
->data
== with_object
);
2733 frame
->scope_chain
= g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2737 swfdec_action_with (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2739 SwfdecAsObject
*object
;
2743 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2744 swfdec_as_stack_pop (cx
);
2747 offset
= data
[0] | (data
[1] << 8);
2748 object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 1));
2749 if (object
== NULL
) {
2750 SWFDEC_INFO ("With called without an object, skipping");
2751 cx
->frame
->pc
= (guint8
*) data
+ len
+ offset
;
2753 cx
->frame
->scope_chain
= g_slist_prepend (cx
->frame
->scope_chain
, object
);
2754 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ offset
,
2755 swfdec_action_pop_with
, object
);
2757 swfdec_as_stack_pop (cx
);
2761 swfdec_action_remove_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2763 if (!SWFDEC_IS_MOVIE (cx
->frame
->target
)) {
2764 SWFDEC_FIXME ("target is not a movie in RemoveSprite");
2765 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2766 SWFDEC_INFO ("tried using RemoveSprite in a non-SwfdecPlayer context");
2768 SwfdecMovie
*movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2769 swfdec_as_stack_peek (cx
, 1));
2770 if (movie
&& swfdec_depth_classify (movie
->depth
) == SWFDEC_DEPTH_CLASS_DYNAMIC
) {
2771 SWFDEC_LOG ("removing clip %s", movie
->name
);
2772 swfdec_movie_remove (movie
);
2774 SWFDEC_INFO ("cannot remove movie");
2777 swfdec_as_stack_pop (cx
);
2781 swfdec_action_clone_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2783 SwfdecMovie
*movie
, *new_movie
;
2784 const char *new_name
;
2787 depth
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1)) - 16384;
2788 new_name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
2789 if (!SWFDEC_IS_MOVIE (cx
->frame
->target
)) {
2790 SWFDEC_FIXME ("target is not a movie in CloneSprite");
2791 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2792 SWFDEC_INFO ("tried using CloneSprite in a non-SwfdecPlayer context");
2794 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2795 swfdec_as_stack_peek (cx
, 3));
2796 if (movie
== NULL
) {
2797 SWFDEC_ERROR ("Object is not an SwfdecMovie object");
2798 swfdec_as_stack_pop_n (cx
, 3);
2801 new_movie
= swfdec_movie_duplicate (movie
, new_name
, depth
);
2803 SWFDEC_LOG ("duplicated %s as %s to depth %u", movie
->name
, new_movie
->name
, new_movie
->depth
);
2806 swfdec_as_stack_pop_n (cx
, 3);
2809 /*** PRINT FUNCTIONS ***/
2812 swfdec_action_print_with (guint action
, const guint8
*data
, guint len
)
2815 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2818 return g_strdup_printf ("With %u", data
[0] | (data
[1] << 8));
2822 swfdec_action_print_store_register (guint action
, const guint8
*data
, guint len
)
2825 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
2828 return g_strdup_printf ("StoreRegister %u", (guint
) *data
);
2832 swfdec_action_print_set_target (guint action
, const guint8
*data
, guint len
)
2834 if (!memchr (data
, 0, len
)) {
2835 SWFDEC_ERROR ("SetTarget action does not specify a string");
2838 return g_strconcat ("SetTarget ", data
, NULL
);
2842 swfdec_action_print_define_function (guint action
, const guint8
*data
, guint len
)
2846 const char *function_name
;
2847 guint i
, n_args
, size
;
2848 gboolean v2
= (action
== 0x8e);
2850 string
= g_string_new (v2
? "DefineFunction2 " : "DefineFunction ");
2851 swfdec_bits_init_data (&bits
, data
, len
);
2852 function_name
= swfdec_bits_get_string (&bits
);
2853 if (function_name
== NULL
) {
2854 SWFDEC_ERROR ("could not parse function name");
2855 g_string_free (string
, TRUE
);
2858 if (*function_name
) {
2859 g_string_append (string
, function_name
);
2860 g_string_append_c (string
, ' ');
2862 n_args
= swfdec_bits_get_u16 (&bits
);
2863 g_string_append_c (string
, '(');
2865 /* n_regs = */ swfdec_bits_get_u8 (&bits
);
2866 /* flags = */ swfdec_bits_get_u16 (&bits
);
2869 for (i
= 0; i
< n_args
; i
++) {
2871 const char *arg_name
;
2873 preload
= swfdec_bits_get_u8 (&bits
);
2876 arg_name
= swfdec_bits_get_string (&bits
);
2877 if (preload
== 0 && (arg_name
== NULL
|| *arg_name
== '\0')) {
2878 SWFDEC_ERROR ("empty argument name not allowed");
2879 g_string_free (string
, TRUE
);
2883 g_string_append (string
, ", ");
2884 g_string_append (string
, arg_name
);
2886 g_string_append_printf (string
, " (%u)", preload
);
2888 g_string_append_c (string
, ')');
2889 size
= swfdec_bits_get_u16 (&bits
);
2890 g_string_append_printf (string
, " %u", size
);
2891 return g_string_free (string
, FALSE
);
2895 swfdec_action_print_get_url2 (guint action
, const guint8
*data
, guint len
)
2900 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
2903 method
= data
[0] >> 6;
2905 SWFDEC_ERROR ("GetURL method 3 invalid");
2909 SWFDEC_FIXME ("implement encoding variables using %s", method
== 1 ? "GET" : "POST");
2911 return g_strdup_printf ("GetURL2%s%s%s", method
== 0 ? "" : (method
== 1 ? " GET" : " POST"),
2912 data
[0] & 2 ? " LoadTarget" : "", data
[0] & 1 ? " LoadVariables" : "");
2916 swfdec_action_print_get_url (guint action
, const guint8
*data
, guint len
)
2919 char *url
, *target
, *ret
;
2921 swfdec_bits_init_data (&bits
, data
, len
);
2922 url
= swfdec_bits_get_string (&bits
);
2923 target
= swfdec_bits_get_string (&bits
);
2925 SWFDEC_ERROR ("not enough data in GetURL");
2926 url
= g_strdup ("???");
2928 if (target
== NULL
) {
2929 SWFDEC_ERROR ("not enough data in GetURL");
2930 target
= g_strdup ("???");
2932 if (swfdec_bits_left (&bits
)) {
2933 SWFDEC_WARNING ("leftover bytes in GetURL action");
2935 ret
= g_strdup_printf ("GetURL %s %s", url
, target
);
2942 swfdec_action_print_if (guint action
, const guint8
*data
, guint len
)
2945 SWFDEC_ERROR ("If action length invalid (is %u, should be 2", len
);
2948 return g_strdup_printf ("If %d", GINT16_FROM_LE (*((gint16
*) data
)));
2952 swfdec_action_print_jump (guint action
, const guint8
*data
, guint len
)
2955 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2", len
);
2958 return g_strdup_printf ("Jump %d", GINT16_FROM_LE (*((gint16
*) data
)));
2962 swfdec_action_print_push (guint action
, const guint8
*data
, guint len
)
2964 gboolean first
= TRUE
;
2966 GString
*string
= g_string_new ("Push");
2968 swfdec_bits_init_data (&bits
, data
, len
);
2969 while (swfdec_bits_left (&bits
)) {
2970 guint type
= swfdec_bits_get_u8 (&bits
);
2972 g_string_append (string
, " ");
2974 g_string_append (string
, ", ");
2977 case 0: /* string */
2979 /* FIXME: need version! */
2980 char *s
= swfdec_bits_get_string (&bits
);
2982 g_string_free (string
, TRUE
);
2985 g_string_append_c (string
, '"');
2986 g_string_append (string
, s
);
2987 g_string_append_c (string
, '"');
2992 g_string_append_printf (string
, "%g", swfdec_bits_get_float (&bits
));
2995 g_string_append (string
, "null");
2997 case 3: /* undefined */
2998 g_string_append (string
, "void");
3000 case 4: /* register */
3001 g_string_append_printf (string
, "Register %u", swfdec_bits_get_u8 (&bits
));
3003 case 5: /* boolean */
3004 g_string_append (string
, swfdec_bits_get_u8 (&bits
) ? "True" : "False");
3006 case 6: /* double */
3007 g_string_append_printf (string
, "%g", swfdec_bits_get_double (&bits
));
3009 case 7: /* 32bit int */
3010 g_string_append_printf (string
, "%d", swfdec_bits_get_u32 (&bits
));
3012 case 8: /* 8bit ConstantPool address */
3013 g_string_append_printf (string
, "Pool %u", swfdec_bits_get_u8 (&bits
));
3015 case 9: /* 16bit ConstantPool address */
3016 g_string_append_printf (string
, "Pool %u", swfdec_bits_get_u16 (&bits
));
3019 SWFDEC_ERROR ("Push: type %u not implemented", type
);
3023 return g_string_free (string
, FALSE
);
3026 /* NB: constant pool actions are special in that they are called at init time */
3028 swfdec_action_print_constant_pool (guint action
, const guint8
*data
, guint len
)
3032 SwfdecConstantPool
*pool
;
3034 /* FIXME: version */
3035 pool
= swfdec_constant_pool_new_from_action (data
, len
, 6);
3037 return g_strdup ("ConstantPool (invalid)");
3038 string
= g_string_new ("ConstantPool");
3039 for (i
= 0; i
< swfdec_constant_pool_size (pool
); i
++) {
3040 g_string_append (string
, i
? ", " : " ");
3041 g_string_append (string
, swfdec_constant_pool_get (pool
, i
));
3042 g_string_append_printf (string
, " (%u)", i
);
3044 return g_string_free (string
, FALSE
);
3049 swfdec_action_print_wait_for_frame2 (guint action
, const guint8
*data
, guint len
)
3052 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
3055 return g_strdup_printf ("WaitForFrame2 %u", (guint
) *data
);
3060 swfdec_action_print_goto_frame2 (guint action
, const guint8
*data
, guint len
)
3062 gboolean play
, bias
;
3065 swfdec_bits_init_data (&bits
, data
, len
);
3066 if (swfdec_bits_getbits (&bits
, 6)) {
3067 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
3069 bias
= swfdec_bits_getbit (&bits
);
3070 play
= swfdec_bits_getbit (&bits
);
3072 return g_strdup_printf ("GotoFrame2 %s +%u", play
? "play" : "stop",
3073 swfdec_bits_get_u16 (&bits
));
3075 return g_strdup_printf ("GotoFrame2 %s", play
? "play" : "stop");
3080 swfdec_action_print_goto_frame (guint action
, const guint8
*data
, guint len
)
3087 frame
= data
[0] | (data
[1] << 8);
3088 return g_strdup_printf ("GotoFrame %u", frame
);
3092 swfdec_action_print_goto_label (guint action
, const guint8
*data
, guint len
)
3094 if (!memchr (data
, 0, len
)) {
3095 SWFDEC_ERROR ("GotoLabel action does not specify a string");
3099 return g_strdup_printf ("GotoLabel %s", data
);
3103 swfdec_action_print_wait_for_frame (guint action
, const guint8
*data
, guint len
)
3110 frame
= data
[0] | (data
[1] << 8);
3112 return g_strdup_printf ("WaitForFrame %u %u", frame
, jump
);
3115 /*** BIG FUNCTION TABLE ***/
3117 const SwfdecActionSpec swfdec_as_actions
[256] = {
3119 [SWFDEC_AS_ACTION_NEXT_FRAME
] = { "NextFrame", NULL
, 0, 0, swfdec_action_next_frame
, 1 },
3120 [SWFDEC_AS_ACTION_PREVIOUS_FRAME
] = { "PreviousFrame", NULL
, 0, 0, swfdec_action_previous_frame
, 1 },
3121 [SWFDEC_AS_ACTION_PLAY
] = { "Play", NULL
, 0, 0, swfdec_action_play
, 1 },
3122 [SWFDEC_AS_ACTION_STOP
] = { "Stop", NULL
, 0, 0, swfdec_action_stop
, 1 },
3123 [SWFDEC_AS_ACTION_TOGGLE_QUALITY
] = { "ToggleQuality", NULL
, -1, -1, NULL
, 1 },
3125 [SWFDEC_AS_ACTION_STOP_SOUNDS
] = { "StopSounds", NULL
, 0, 0, swfdec_action_stop_sounds
, 2 },
3127 [SWFDEC_AS_ACTION_ADD
] = { "Add", NULL
, 2, 1, swfdec_action_binary
, 4 },
3128 [SWFDEC_AS_ACTION_SUBTRACT
] = { "Subtract", NULL
, 2, 1, swfdec_action_binary
, 4 },
3129 [SWFDEC_AS_ACTION_MULTIPLY
] = { "Multiply", NULL
, 2, 1, swfdec_action_binary
, 4 },
3130 [SWFDEC_AS_ACTION_DIVIDE
] = { "Divide", NULL
, 2, 1, swfdec_action_binary
, 4 },
3131 [SWFDEC_AS_ACTION_EQUALS
] = { "Equals", NULL
, 2, 1, swfdec_action_old_compare
, 4 },
3132 [SWFDEC_AS_ACTION_LESS
] = { "Less", NULL
, 2, 1, swfdec_action_old_compare
, 4 },
3133 [SWFDEC_AS_ACTION_AND
] = { "And", NULL
, 2, 1, swfdec_action_logical
, 4 },
3134 [SWFDEC_AS_ACTION_OR
] = { "Or", NULL
, 2, 1, swfdec_action_logical
, 4 },
3135 [SWFDEC_AS_ACTION_NOT
] = { "Not", NULL
, 1, 1, swfdec_action_not
, 4 },
3136 [SWFDEC_AS_ACTION_STRING_EQUALS
] = { "StringEquals", NULL
, 2, 1, swfdec_action_string_compare
, 4 },
3137 [SWFDEC_AS_ACTION_STRING_LENGTH
] = { "StringLength", NULL
, 1, 1, swfdec_action_string_length
, 4 },
3138 [SWFDEC_AS_ACTION_STRING_EXTRACT
] = { "StringExtract", NULL
, 3, 1, swfdec_action_string_extract
, 4 },
3139 [SWFDEC_AS_ACTION_POP
] = { "Pop", NULL
, 1, 0, swfdec_action_pop
, 4 },
3140 [SWFDEC_AS_ACTION_TO_INTEGER
] = { "ToInteger", NULL
, 1, 1, swfdec_action_to_integer
, 4 },
3141 [SWFDEC_AS_ACTION_GET_VARIABLE
] = { "GetVariable", NULL
, 1, 1, swfdec_action_get_variable
, 4 },
3142 [SWFDEC_AS_ACTION_SET_VARIABLE
] = { "SetVariable", NULL
, 2, 0, swfdec_action_set_variable
, 4 },
3144 [SWFDEC_AS_ACTION_SET_TARGET2
] = { "SetTarget2", NULL
, 1, 0, swfdec_action_set_target2
, 3 },
3146 [SWFDEC_AS_ACTION_STRING_ADD
] = { "StringAdd", NULL
, 2, 1, swfdec_action_string_add
, 4 },
3147 [SWFDEC_AS_ACTION_GET_PROPERTY
] = { "GetProperty", NULL
, 2, 1, swfdec_action_get_property
, 4 },
3148 [SWFDEC_AS_ACTION_SET_PROPERTY
] = { "SetProperty", NULL
, 3, 0, swfdec_action_set_property
, 4 },
3149 [SWFDEC_AS_ACTION_CLONE_SPRITE
] = { "CloneSprite", NULL
, 3, 0, swfdec_action_clone_sprite
, 4 },
3150 [SWFDEC_AS_ACTION_REMOVE_SPRITE
] = { "RemoveSprite", NULL
, 1, 0, swfdec_action_remove_sprite
, 4 },
3151 [SWFDEC_AS_ACTION_TRACE
] = { "Trace", NULL
, 1, 0, swfdec_action_trace
, 4 },
3152 [SWFDEC_AS_ACTION_START_DRAG
] = { "StartDrag", NULL
, -1, 0, swfdec_action_start_drag
, 4 },
3153 [SWFDEC_AS_ACTION_END_DRAG
] = { "EndDrag", NULL
, 0, 0, swfdec_action_end_drag
, 4 },
3154 [SWFDEC_AS_ACTION_STRING_LESS
] = { "StringLess", NULL
, 2, 1, swfdec_action_string_compare
, 4 },
3156 [SWFDEC_AS_ACTION_THROW
] = { "Throw", NULL
, 1, 0, swfdec_action_throw
, 7 },
3157 [SWFDEC_AS_ACTION_CAST
] = { "Cast", NULL
, 2, 1, swfdec_action_cast
, 7 },
3158 [SWFDEC_AS_ACTION_IMPLEMENTS
] = { "Implements", NULL
, -1, 0, swfdec_action_implements
, 7 },
3160 [SWFDEC_AS_ACTION_RANDOM
] = { "RandomNumber", NULL
, 1, 1, swfdec_action_random_number
, 4 },
3161 [SWFDEC_AS_ACTION_MB_STRING_LENGTH
] = { "MBStringLength", NULL
, -1, -1, NULL
, 4 },
3162 [SWFDEC_AS_ACTION_CHAR_TO_ASCII
] = { "CharToAscii", NULL
, 1, 1, swfdec_action_char_to_ascii
, 4 },
3163 [SWFDEC_AS_ACTION_ASCII_TO_CHAR
] = { "AsciiToChar", NULL
, 1, 1, swfdec_action_ascii_to_char
, 4 },
3164 [SWFDEC_AS_ACTION_GET_TIME
] = { "GetTime", NULL
, 0, 1, swfdec_action_get_time
, 4 },
3165 [SWFDEC_AS_ACTION_MB_STRING_EXTRACT
] = { "MBStringExtract", NULL
, 3, 1, swfdec_action_string_extract
, 4 },
3166 [SWFDEC_AS_ACTION_MB_CHAR_TO_ASCII
] = { "MBCharToAscii", NULL
, -1, -1, NULL
, 4 },
3167 [SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
] = { "MBAsciiToChar", NULL
, 1, 1, swfdec_action_ascii_to_char
, 4 },
3169 [SWFDEC_AS_ACTION_DELETE
] = { "Delete", NULL
, 2, 1, swfdec_action_delete
, 5 },
3170 [SWFDEC_AS_ACTION_DELETE2
] = { "Delete2", NULL
, 1, 1, swfdec_action_delete2
, 5 },
3171 [SWFDEC_AS_ACTION_DEFINE_LOCAL
] = { "DefineLocal", NULL
, 2, 0, swfdec_action_define_local
, 5 },
3172 [SWFDEC_AS_ACTION_CALL_FUNCTION
] = { "CallFunction", NULL
, -1, 1, swfdec_action_call_function
, 5 },
3173 [SWFDEC_AS_ACTION_RETURN
] = { "Return", NULL
, 1, 0, swfdec_action_return
, 5 },
3174 [SWFDEC_AS_ACTION_MODULO
] = { "Modulo", NULL
, 2, 1, swfdec_action_modulo
, 5 },
3175 [SWFDEC_AS_ACTION_NEW_OBJECT
] = { "NewObject", NULL
, -1, 1, swfdec_action_new_object
, 5 },
3176 [SWFDEC_AS_ACTION_DEFINE_LOCAL2
] = { "DefineLocal2", NULL
, 1, 0, swfdec_action_define_local2
, 5 },
3177 [SWFDEC_AS_ACTION_INIT_ARRAY
] = { "InitArray", NULL
, -1, 1, swfdec_action_init_array
, 5 },
3178 [SWFDEC_AS_ACTION_INIT_OBJECT
] = { "InitObject", NULL
, -1, 1, swfdec_action_init_object
, 5 },
3179 [SWFDEC_AS_ACTION_TYPE_OF
] = { "TypeOf", NULL
, 1, 1, swfdec_action_type_of
, 5 },
3180 [SWFDEC_AS_ACTION_TARGET_PATH
] = { "TargetPath", NULL
, 1, 1, swfdec_action_target_path
, 5 },
3181 [SWFDEC_AS_ACTION_ENUMERATE
] = { "Enumerate", NULL
, 1, -1, swfdec_action_enumerate
, 5 },
3182 [SWFDEC_AS_ACTION_ADD2
] = { "Add2", NULL
, 2, 1, swfdec_action_add2
, 5 },
3183 [SWFDEC_AS_ACTION_LESS2
] = { "Less2", NULL
, 2, 1, swfdec_action_new_comparison
, 5 },
3184 [SWFDEC_AS_ACTION_EQUALS2
] = { "Equals2", NULL
, 2, 1, swfdec_action_equals2
, 5 },
3185 [SWFDEC_AS_ACTION_TO_NUMBER
] = { "ToNumber", NULL
, 1, 1, swfdec_action_to_number
, 5 },
3186 [SWFDEC_AS_ACTION_TO_STRING
] = { "ToString", NULL
, 1, 1, swfdec_action_to_string
, 5 },
3187 [SWFDEC_AS_ACTION_PUSH_DUPLICATE
] = { "PushDuplicate", NULL
, 1, 2, swfdec_action_push_duplicate
, 5 },
3188 [SWFDEC_AS_ACTION_SWAP
] = { "Swap", NULL
, 2, 2, swfdec_action_swap
, 5 },
3190 [SWFDEC_AS_ACTION_GET_MEMBER
] = { "GetMember", NULL
, 2, 1, swfdec_action_get_member
, 4 },
3191 [SWFDEC_AS_ACTION_SET_MEMBER
] = { "SetMember", NULL
, 3, 0, swfdec_action_set_member
, 4 },
3193 [SWFDEC_AS_ACTION_INCREMENT
] = { "Increment", NULL
, 1, 1, swfdec_action_increment
, 5 },
3194 [SWFDEC_AS_ACTION_DECREMENT
] = { "Decrement", NULL
, 1, 1, swfdec_action_decrement
, 5 },
3195 [SWFDEC_AS_ACTION_CALL_METHOD
] = { "CallMethod", NULL
, -1, 1, swfdec_action_call_method
, 5 },
3196 [SWFDEC_AS_ACTION_NEW_METHOD
] = { "NewMethod", NULL
, -1, 1, swfdec_action_new_method
, 5 },
3198 [SWFDEC_AS_ACTION_INSTANCE_OF
] = { "InstanceOf", NULL
, 2, 1, swfdec_action_instance_of
, 6 },
3199 [SWFDEC_AS_ACTION_ENUMERATE2
] = { "Enumerate2", NULL
, 1, -1, swfdec_action_enumerate2
, 6 },
3200 [SWFDEC_AS_ACTION_BREAKPOINT
] = { "Breakpoint", NULL
, -1, -1, NULL
, 6 },
3202 [SWFDEC_AS_ACTION_BIT_AND
] = { "BitAnd", NULL
, 2, 1, swfdec_action_bitwise
, 5 },
3203 [SWFDEC_AS_ACTION_BIT_OR
] = { "BitOr", NULL
, 2, 1, swfdec_action_bitwise
, 5 },
3204 [SWFDEC_AS_ACTION_BIT_XOR
] = { "BitXor", NULL
, 2, 1, swfdec_action_bitwise
, 5 },
3205 [SWFDEC_AS_ACTION_BIT_LSHIFT
] = { "BitLShift", NULL
, 2, 1, swfdec_action_shift
, 5 },
3206 [SWFDEC_AS_ACTION_BIT_RSHIFT
] = { "BitRShift", NULL
, 2, 1, swfdec_action_shift
, 5 },
3207 [SWFDEC_AS_ACTION_BIT_URSHIFT
] = { "BitURShift", NULL
, 2, 1, swfdec_action_shift
, 5 },
3209 [SWFDEC_AS_ACTION_STRICT_EQUALS
] = { "StrictEquals", NULL
, 2, 1, swfdec_action_strict_equals
, 6 },
3210 [SWFDEC_AS_ACTION_GREATER
] = { "Greater", NULL
, 2, 1, swfdec_action_new_comparison
, 6 },
3211 [SWFDEC_AS_ACTION_STRING_GREATER
] = { "StringGreater", NULL
, -1, -1, NULL
, 6 },
3213 [SWFDEC_AS_ACTION_EXTENDS
] = { "Extends", NULL
, 2, 0, swfdec_action_extends
, 7 },
3215 [SWFDEC_AS_ACTION_GOTO_FRAME
] = { "GotoFrame", swfdec_action_print_goto_frame
, 0, 0, swfdec_action_goto_frame
, 1 },
3216 [SWFDEC_AS_ACTION_GET_URL
] = { "GetURL", swfdec_action_print_get_url
, 0, 0, swfdec_action_get_url
, 1 },
3218 [SWFDEC_AS_ACTION_STORE_REGISTER
] = { "StoreRegister", swfdec_action_print_store_register
, 1, 1, swfdec_action_store_register
, 5 },
3219 [SWFDEC_AS_ACTION_CONSTANT_POOL
] = { "ConstantPool", swfdec_action_print_constant_pool
, 0, 0, swfdec_action_constant_pool
, 5 },
3220 [SWFDEC_AS_ACTION_STRICT_MODE
] = { "StrictMode", NULL
, -1, -1, NULL
, 5 },
3222 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME
] = { "WaitForFrame", swfdec_action_print_wait_for_frame
, 0, 0, swfdec_action_wait_for_frame
, 1 },
3223 [SWFDEC_AS_ACTION_SET_TARGET
] = { "SetTarget", swfdec_action_print_set_target
, 0, 0, swfdec_action_set_target
, 1 },
3225 [SWFDEC_AS_ACTION_GOTO_LABEL
] = { "GotoLabel", swfdec_action_print_goto_label
, 0, 0, swfdec_action_goto_label
, 3 },
3228 [0x8d] = { "WaitForFrame2", swfdec_action_print_wait_for_frame2
, 1, 0, { NULL
, swfdec_action_wait_for_frame2
, swfdec_action_wait_for_frame2
, swfdec_action_wait_for_frame2
, swfdec_action_wait_for_frame2
} },
3231 [SWFDEC_AS_ACTION_DEFINE_FUNCTION2
] = { "DefineFunction2", swfdec_action_print_define_function
, 0, -1, swfdec_action_define_function
, 7 },
3232 [SWFDEC_AS_ACTION_TRY
] = { "Try", NULL
, 0, 0, swfdec_action_try
, 7 },
3234 [SWFDEC_AS_ACTION_WITH
] = { "With", swfdec_action_print_with
, 1, 0, swfdec_action_with
, 5 },
3236 [SWFDEC_AS_ACTION_PUSH
] = { "Push", swfdec_action_print_push
, 0, -1, swfdec_action_push
, 4 },
3237 [SWFDEC_AS_ACTION_JUMP
] = { "Jump", swfdec_action_print_jump
, 0, 0, swfdec_action_jump
, 4 },
3238 [SWFDEC_AS_ACTION_GET_URL2
] = { "GetURL2", swfdec_action_print_get_url2
, 2, 0, swfdec_action_get_url2
, 4 },
3240 [SWFDEC_AS_ACTION_DEFINE_FUNCTION
] = { "DefineFunction", swfdec_action_print_define_function
, 0, -1, swfdec_action_define_function
, 5 },
3242 [SWFDEC_AS_ACTION_IF
] = { "If", swfdec_action_print_if
, 1, 0, swfdec_action_if
, 4 },
3243 [SWFDEC_AS_ACTION_CALL
] = { "Call", NULL
, -1, -1, NULL
, 4 },
3244 [SWFDEC_AS_ACTION_GOTO_FRAME2
] = { "GotoFrame2", swfdec_action_print_goto_frame2
, 1, 0, swfdec_action_goto_frame2
, 4 }