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 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
67 if (SWFDEC_IS_SPRITE_MOVIE (target
))
68 SWFDEC_SPRITE_MOVIE (target
)->playing
= FALSE
;
70 SWFDEC_ERROR ("no movie to stop");
74 swfdec_action_play (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
76 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
77 if (SWFDEC_IS_SPRITE_MOVIE(target
))
78 SWFDEC_SPRITE_MOVIE (target
)->playing
= TRUE
;
80 SWFDEC_ERROR ("no movie to play");
84 swfdec_action_next_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
86 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
87 if (SWFDEC_IS_SPRITE_MOVIE (target
)) {
88 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (target
);
89 if (movie
->frame
< movie
->n_frames
) {
90 swfdec_sprite_movie_goto (movie
, movie
->frame
+ 1);
91 movie
->playing
= FALSE
;
93 SWFDEC_INFO ("can't execute nextFrame, already at last frame");
96 SWFDEC_ERROR ("no movie to nextFrame on");
101 swfdec_action_previous_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
103 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
104 if (SWFDEC_IS_SPRITE_MOVIE (target
)) {
105 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (target
);
106 if (movie
->frame
> 1) {
107 swfdec_sprite_movie_goto (movie
, movie
->frame
- 1);
108 movie
->playing
= FALSE
;
110 SWFDEC_INFO ("can't execute previousFrame, already at first frame");
113 SWFDEC_ERROR ("no movie to previousFrame on");
118 swfdec_action_goto_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
124 SWFDEC_ERROR ("GotoFrame action length invalid (is %u, should be 2", len
);
127 frame
= data
[0] | (data
[1] << 8);
128 target
= swfdec_as_frame_get_target (cx
->frame
);
129 if (SWFDEC_IS_SPRITE_MOVIE (target
)) {
130 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (target
);
131 swfdec_sprite_movie_goto (movie
, frame
+ 1);
132 movie
->playing
= FALSE
;
134 SWFDEC_ERROR ("no movie to goto on");
139 swfdec_action_goto_label (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
142 if (!memchr (data
, 0, len
)) {
143 SWFDEC_ERROR ("GotoLabel action does not specify a string");
147 target
= swfdec_as_frame_get_target (cx
->frame
);
148 if (SWFDEC_IS_SPRITE_MOVIE (target
)) {
149 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (target
);
151 if (movie
->sprite
== NULL
||
152 (frame
= swfdec_sprite_get_frame (movie
->sprite
, (const char *) data
)) == -1)
154 swfdec_sprite_movie_goto (movie
, frame
+ 1);
155 movie
->playing
= FALSE
;
157 SWFDEC_ERROR ("no movie to goto on");
161 /* returns: frame to go to or 0 on error */
163 swfdec_value_to_frame (SwfdecAsContext
*cx
, SwfdecSpriteMovie
*movie
, SwfdecAsValue
*val
)
167 if (movie
->sprite
== NULL
)
169 if (SWFDEC_AS_VALUE_IS_STRING (*val
)) {
170 const char *name
= SWFDEC_AS_VALUE_GET_STRING (*val
);
172 if (strchr (name
, ':')) {
173 SWFDEC_ERROR ("FIXME: handle targets");
175 /* treat valid encoded numbers as numbers, otherwise assume it's a frame label */
176 d
= swfdec_as_value_to_number (cx
, *val
);
178 frame
= swfdec_sprite_get_frame (movie
->sprite
, name
) + 1;
181 } else if (SWFDEC_AS_VALUE_IS_NUMBER (*val
)) {
182 frame
= swfdec_as_value_to_integer (cx
, *val
);
184 SWFDEC_WARNING ("cannot convert value to frame number");
185 /* FIXME: how do we treat undefined etc? */
188 return frame
<= 0 ? 0 : frame
;
192 swfdec_action_goto_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
200 swfdec_bits_init_data (&bits
, data
, len
);
201 if (swfdec_bits_getbits (&bits
, 6)) {
202 SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0");
204 bias
= swfdec_bits_getbit (&bits
);
205 play
= swfdec_bits_getbit (&bits
);
207 bias
= swfdec_bits_get_u16 (&bits
);
209 val
= swfdec_as_stack_peek (cx
, 1);
211 target
= swfdec_as_frame_get_target (cx
->frame
);
212 if (SWFDEC_IS_SPRITE_MOVIE (target
)) {
213 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (target
);
214 guint frame
= swfdec_value_to_frame (cx
, movie
, val
);
217 frame
= CLAMP (frame
, 1, movie
->n_frames
);
218 swfdec_sprite_movie_goto (movie
, frame
);
219 movie
->playing
= play
;
222 SWFDEC_ERROR ("no movie to GotoFrame2 on");
224 swfdec_as_stack_pop (cx
);
228 swfdec_script_skip_actions (SwfdecAsContext
*cx
, guint jump
)
230 SwfdecScript
*script
= cx
->frame
->script
;
231 const guint8
*pc
= cx
->frame
->pc
;
232 const guint8
*endpc
= script
->buffer
->data
+ script
->buffer
->length
;
234 /* jump instructions */
241 pc
+= 3 + (pc
[1] | (pc
[2] << 8));
245 } while (jump
-- > 0);
250 swfdec_action_wait_for_frame2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
252 SwfdecSpriteMovie
*movie
;
257 SWFDEC_ERROR ("WaitForFrame2 needs a 1-byte data");
260 target
= swfdec_as_frame_get_target (cx
->frame
);
261 if (!SWFDEC_IS_SPRITE_MOVIE (target
)) {
262 SWFDEC_ERROR ("no movie for WaitForFrame");
266 movie
= SWFDEC_SPRITE_MOVIE (target
);
267 frame
= swfdec_value_to_frame (cx
, movie
, swfdec_as_stack_pop (cx
));
268 loaded
= swfdec_sprite_movie_get_frames_loaded (movie
);
269 if (loaded
< (int) movie
->n_frames
&&
271 swfdec_script_skip_actions (cx
, data
[0]);
275 swfdec_action_wait_for_frame (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
277 SwfdecSpriteMovie
*movie
;
283 SWFDEC_ERROR ("WaitForFrame action length invalid (is %u, should be 3", len
);
286 target
= swfdec_as_frame_get_target (cx
->frame
);
287 if (!SWFDEC_IS_SPRITE_MOVIE (target
)) {
288 SWFDEC_ERROR ("no movie for WaitForFrame");
292 movie
= SWFDEC_SPRITE_MOVIE (target
);
293 frame
= data
[0] | (data
[1] << 8);
295 loaded
= swfdec_sprite_movie_get_frames_loaded (movie
);
296 if (loaded
< (int) movie
->n_frames
&&
298 swfdec_script_skip_actions (cx
, jump
);
302 swfdec_action_constant_pool (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
304 SwfdecConstantPool
*pool
;
305 SwfdecAsFrame
*frame
;
306 SwfdecBuffer
*buffer
;
309 /* FIXME: lots of hackery to get at the buffer */
310 buffer
= frame
->script
->buffer
;
311 buffer
= swfdec_buffer_new_subbuffer (buffer
, data
- buffer
->data
, len
);
312 pool
= swfdec_constant_pool_new (cx
, buffer
, cx
->version
);
313 swfdec_buffer_unref (buffer
);
316 if (frame
->constant_pool
)
317 swfdec_constant_pool_unref (frame
->constant_pool
);
318 frame
->constant_pool
= pool
;
322 swfdec_action_push (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
326 swfdec_bits_init_data (&bits
, data
, len
);
327 while (swfdec_bits_left (&bits
)) {
328 guint type
= swfdec_bits_get_u8 (&bits
);
329 SWFDEC_LOG ("push type %u", type
);
330 swfdec_as_stack_ensure_free (cx
, 1);
334 char *s
= swfdec_bits_get_string (&bits
, cx
->version
);
336 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
337 SWFDEC_AS_STR_EMPTY
);
339 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
340 swfdec_as_context_give_string (cx
, s
));
345 *swfdec_as_stack_push (cx
) = swfdec_as_value_from_number (cx
,
346 swfdec_bits_get_float (&bits
));
349 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
351 case 3: /* undefined */
352 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
354 case 4: /* register */
356 guint regnum
= swfdec_bits_get_u8 (&bits
);
357 if (!swfdec_action_has_register (cx
, regnum
)) {
358 SWFDEC_ERROR ("cannot Push register %u: not enough registers", regnum
);
359 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
361 *swfdec_as_stack_push (cx
) = cx
->frame
->registers
[regnum
];
365 case 5: /* boolean */
366 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
367 swfdec_bits_get_u8 (&bits
) ? TRUE
: FALSE
);
370 *swfdec_as_stack_push (cx
) = swfdec_as_value_from_number (cx
,
371 swfdec_bits_get_double (&bits
));
373 case 7: /* 32bit int */
374 *swfdec_as_stack_push (cx
) = swfdec_as_value_from_integer (cx
,
375 swfdec_bits_get_s32 (&bits
));
377 case 8: /* 8bit ConstantPool address */
378 case 9: /* 16bit ConstantPool address */
380 guint i
= type
== 8 ? swfdec_bits_get_u8 (&bits
) : swfdec_bits_get_u16 (&bits
);
381 SwfdecConstantPool
*pool
= cx
->frame
->constant_pool
;
383 SWFDEC_ERROR ("no constant pool to push from");
384 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
387 if (i
>= swfdec_constant_pool_size (pool
)) {
388 SWFDEC_ERROR ("constant pool index %u too high - only %u elements",
389 i
, swfdec_constant_pool_size (pool
));
390 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
393 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
),
394 swfdec_constant_pool_get (pool
, i
));
398 SWFDEC_ERROR ("Push: unknown type %u, skipping", type
);
404 /* NB: name must be GC'd */
405 static SwfdecAsObject
*
406 super_special_movie_lookup_magic (SwfdecAsContext
*cx
, SwfdecAsObject
*o
, const char *name
)
411 o
= swfdec_as_frame_get_variable (cx
, cx
->frame
, name
, NULL
);
416 SwfdecMovie
*ret
= swfdec_movie_get_by_name (SWFDEC_MOVIE (o
->relay
), name
, TRUE
);
418 return swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (ret
));
420 if (!swfdec_as_object_get_variable (o
, name
, &val
))
422 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (val
))
424 return SWFDEC_AS_VALUE_GET_COMPOSITE (val
);
427 static SwfdecAsObject
*
428 swfdec_action_get_movie_by_slash_path (SwfdecAsContext
*cx
, const char *path
)
433 movie
= swfdec_as_frame_get_target (cx
->frame
);
437 movie
= swfdec_movie_get_root (movie
);
440 o
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
));
442 char *slash
= strchr (path
, '/');
447 name
= swfdec_as_context_give_string (cx
, g_strndup (path
, slash
- path
));
450 name
= swfdec_as_context_get_string (cx
, path
);
451 path
+= strlen (path
);
453 o
= super_special_movie_lookup_magic (cx
, o
, name
);
454 if (o
== NULL
|| !o
->movie
)
461 swfdec_action_lookup_object (SwfdecAsContext
*cx
, SwfdecAsObject
*o
, const char *path
, const char *end
)
463 gboolean dot_allowed
= TRUE
;
468 SwfdecMovie
*movie
= swfdec_as_frame_get_target (cx
->frame
);
470 o
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
));
475 if (path
[0] == '/') {
477 SwfdecMovie
*movie
= swfdec_as_frame_get_target (cx
->frame
);
479 movie
= swfdec_movie_get_root (movie
);
480 o
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
));
489 for (start
= path
; path
< end
; path
++) {
490 if (dot_allowed
&& path
[0] == '.') {
491 if (end
- path
>= 2 && path
[1] == '.') {
495 } else if (path
[0] == ':') {
502 } else if (path
[0] == '/') {
504 } else if (path
- start
< 127) {
512 if (start
[0] == '.' && start
[1] == '.' && start
+ 2 == path
) {
514 /* ".." goes back to parent */
517 for (walk
= cx
->frame
->scope_chain
; walk
; walk
= walk
->next
) {
520 movie
= SWFDEC_MOVIE (o
->relay
);
525 movie
= swfdec_as_frame_get_target (cx
->frame
);
528 } else if (o
->movie
) {
529 movie
= SWFDEC_MOVIE (o
->relay
);
533 movie
= movie
->parent
;
536 o
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
));
538 o
= super_special_movie_lookup_magic (cx
, o
,
539 swfdec_as_context_give_string (cx
, g_strndup (start
, path
- start
)));
543 if (path
- start
< 127)
550 /* FIXME: this function belongs into swfdec_movie.c */
552 swfdec_player_get_movie_from_value (SwfdecPlayer
*player
, SwfdecAsValue
*val
)
557 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
559 cx
= SWFDEC_AS_CONTEXT (player
);
560 s
= swfdec_as_value_to_string (cx
, *val
);
561 return swfdec_player_get_movie_from_string (player
, s
);
565 swfdec_player_get_movie_from_string (SwfdecPlayer
*player
, const char *s
)
569 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
570 g_return_val_if_fail (s
!= NULL
, NULL
);
572 ret
= swfdec_action_lookup_object (SWFDEC_AS_CONTEXT (player
), NULL
, s
, s
+ strlen (s
));
573 if (ret
== NULL
|| !ret
->movie
) {
574 SWFDEC_WARNING ("\"%s\" does not reference a movie", s
);
577 return SWFDEC_MOVIE (ret
->relay
);
581 * swfdec_action_get_movie_by_path:
582 * @cx: a #SwfdecAsContext
583 * @path: the path to look up
584 * @object: pointer that takes the object that was looked up. The object may be
586 * @variable: pointer that takes variable part of the path. The variable will
587 * be either %NULL or a non-gc'ed variable name.
589 * Looks up a Flash4-compatible path using "/", ":" and "." style syntax.
591 * Returns: The #SwfdecMovie that was looked up or %NULL if the path does not
592 * specify a valid movie.
595 swfdec_action_get_movie_by_path (SwfdecAsContext
*cx
, const char *path
,
596 SwfdecAsObject
**object
, const char **variable
)
598 SwfdecAsObject
*movie
;
601 g_assert (path
!= NULL
);
602 g_assert (object
!= NULL
);
603 g_assert (variable
!= NULL
);
604 g_assert (cx
->frame
!= NULL
);
606 /* find dot or colon */
607 end
= strpbrk (path
, ".:");
609 /* if no dot or colon, look up slash-path */
611 /* shortcut for the general case */
612 if (strchr (path
, '/') != NULL
) {
613 movie
= swfdec_action_get_movie_by_slash_path (cx
, path
);
625 /* find last dot or colon */
626 while ((s
= strpbrk (end
+ 1, ".:")) != NULL
)
629 /* variable to use is the part after the last dot or colon */
631 /* look up object for start of path */
635 movie
= swfdec_action_lookup_object (cx
, NULL
, path
, end
);
646 swfdec_action_get_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
650 SwfdecAsObject
*object
;
652 val
= swfdec_as_stack_peek (cx
, 1);
653 s
= swfdec_as_value_to_string (cx
, *val
);
654 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &s
)) {
657 swfdec_as_object_get_variable (object
, swfdec_as_context_get_string (cx
, s
), val
);
659 SWFDEC_AS_VALUE_SET_MOVIE (val
, SWFDEC_MOVIE (object
->relay
));
662 swfdec_as_frame_get_variable (cx
, cx
->frame
, swfdec_as_context_get_string (cx
, s
), val
);
665 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
666 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
667 SWFDEC_WARNING ("no variable named %s", s
);
673 swfdec_action_set_variable (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
675 const char *s
, *rest
;
676 SwfdecAsObject
*object
;
678 s
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
679 if (swfdec_action_get_movie_by_path (cx
, s
, &object
, &rest
)) {
680 if (object
&& rest
) {
681 swfdec_as_object_set_variable (object
, swfdec_as_context_get_string (cx
, rest
),
682 swfdec_as_stack_peek (cx
, 1));
687 rest
= swfdec_as_context_get_string (cx
, rest
);
688 swfdec_as_frame_set_variable (cx
, cx
->frame
, rest
,
689 swfdec_as_stack_peek (cx
, 1), TRUE
, FALSE
);
692 swfdec_as_stack_pop_n (cx
, 2);
696 swfdec_action_get_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
701 id
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1));
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
, 2));
710 SWFDEC_ERROR ("calling GetProperty not on a movieclip object");
711 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
712 } else if (id
> (cx
->version
> 4 ? 21 : 18)) {
713 SWFDEC_WARNING ("trying to GetProperty %u, doesn't exist", id
);
714 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
716 *swfdec_as_stack_peek (cx
, 2) = swfdec_movie_property_get (movie
, id
);
718 swfdec_as_stack_pop (cx
);
722 swfdec_action_set_property (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
727 id
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 2));
728 if (!SWFDEC_IS_PLAYER (cx
)) {
729 SWFDEC_INFO ("tried using GetProperty in a non-SwfdecPlayer context");
732 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
733 swfdec_as_stack_peek (cx
, 3));
736 SWFDEC_ERROR ("calling GetProperty not on a movieclip object");
737 } else if (id
> (cx
->version
> 4 ? 21 : 18)) {
738 SWFDEC_WARNING ("trying to SetProperty %u, doesn't exist", id
);
740 swfdec_movie_property_set (movie
, id
, *swfdec_as_stack_peek (cx
, 1));
742 swfdec_as_stack_pop_n (cx
, 3);
746 swfdec_action_get_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
748 SwfdecAsObject
*object
= swfdec_as_value_to_object (cx
, *swfdec_as_stack_peek (cx
, 2));
751 name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
752 swfdec_as_object_get_variable (object
, name
, swfdec_as_stack_peek (cx
, 2));
753 #ifdef SWFDEC_WARN_MISSING_PROPERTIES
754 if (SWFDEC_AS_VALUE_IS_UNDEFINED (*swfdec_as_stack_peek (cx
, 2))) {
755 SWFDEC_WARNING ("no variable named %s:%s",
756 object
->relay
? G_OBJECT_TYPE_NAME (object
->relay
) : ":", name
);
760 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
762 swfdec_as_stack_pop (cx
);
766 swfdec_action_set_member (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
768 const char *name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
769 if (SWFDEC_AS_VALUE_IS_COMPOSITE (*swfdec_as_stack_peek (cx
, 3))) {
770 SwfdecAsObject
*o
= SWFDEC_AS_VALUE_GET_COMPOSITE (*swfdec_as_stack_peek (cx
, 3));
772 swfdec_as_object_set_variable (o
, name
, swfdec_as_stack_peek (cx
, 1));
774 swfdec_as_stack_pop_n (cx
, 3);
778 swfdec_action_trace (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
783 val
= swfdec_as_stack_peek (cx
, 1);
784 if (SWFDEC_AS_VALUE_IS_UNDEFINED (*val
)) {
785 s
= SWFDEC_AS_STR_undefined
;
787 s
= swfdec_as_value_to_string (cx
, *val
);
789 swfdec_as_stack_pop (cx
);
790 g_signal_emit_by_name (cx
, "trace", s
);
793 /* stack looks like this: [ function, this, arg1, arg2, ... ] */
794 /* stack must be at least 2 elements big */
796 swfdec_action_call (SwfdecAsContext
*cx
, guint n_args
, SwfdecAsObject
*super
)
798 SwfdecAsFunction
*fun
;
799 SwfdecAsObject
*thisp
;
801 if (!SWFDEC_AS_VALUE_IS_OBJECT (*swfdec_as_stack_peek (cx
, 1)))
803 fun
= (SwfdecAsFunction
*) (SWFDEC_AS_VALUE_GET_OBJECT (*swfdec_as_stack_peek (cx
, 1))->relay
);
804 if (!SWFDEC_IS_AS_FUNCTION (fun
))
806 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (*swfdec_as_stack_peek (cx
, 2))) {
809 thisp
= SWFDEC_AS_VALUE_GET_COMPOSITE (*swfdec_as_stack_peek (cx
, 2));
811 swfdec_as_stack_pop_n (cx
, 2);
812 /* sanitize argument count */
813 if (n_args
>= swfdec_as_stack_get_size (cx
))
814 n_args
= swfdec_as_stack_get_size (cx
);
815 if (super
== NULL
&& SWFDEC_IS_AS_SUPER (fun
)) {
816 SWFDEC_LOG ("replacing super object on frame");
817 super
= swfdec_as_super_resolve_property (SWFDEC_AS_SUPER (fun
), NULL
);
819 swfdec_as_function_call_full (fun
, thisp
, FALSE
, super
, n_args
, NULL
, NULL
);
824 if (n_args
> swfdec_as_stack_get_size (cx
))
825 n_args
= swfdec_as_stack_get_size (cx
);
826 swfdec_as_stack_pop_n (cx
, n_args
);
827 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_push (cx
));
832 swfdec_action_call_function (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
834 SwfdecAsFrame
*frame
= cx
->frame
;
838 SwfdecAsValue
*fun
, *thisp
;
840 swfdec_as_stack_ensure_size (cx
, 2);
841 n_args
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 2));
842 name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
843 thisp
= swfdec_as_stack_peek (cx
, 2);
844 fun
= swfdec_as_stack_peek (cx
, 1);
845 obj
= swfdec_as_frame_get_variable (cx
, frame
, name
, fun
);
847 SWFDEC_AS_VALUE_SET_COMPOSITE (thisp
, obj
);
849 SWFDEC_AS_VALUE_SET_NULL (thisp
);
850 SWFDEC_AS_VALUE_SET_UNDEFINED (fun
);
852 if (!swfdec_action_call (cx
, n_args
, NULL
)) {
853 SWFDEC_WARNING ("no function named %s", name
);
858 swfdec_action_call_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
861 SwfdecAsObject
*obj
, *super
;
862 SwfdecAsObject
*pobj
= NULL
;
866 swfdec_as_stack_ensure_size (cx
, 3);
867 obj
= swfdec_as_value_to_object (cx
, *swfdec_as_stack_peek (cx
, 2));
868 n_args
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 3));
869 val
= swfdec_as_stack_peek (cx
, 1);
871 name
= swfdec_as_value_to_string (cx
, *val
);
872 if (SWFDEC_AS_VALUE_IS_UNDEFINED (*val
) ||
873 name
== SWFDEC_AS_STR_EMPTY
) {
874 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 3));
875 SWFDEC_AS_VALUE_SET_COMPOSITE (swfdec_as_stack_peek (cx
, 2), obj
);
879 SWFDEC_AS_VALUE_SET_COMPOSITE (swfdec_as_stack_peek (cx
, 3), obj
);
880 swfdec_as_object_get_variable_and_flags (obj
, name
, swfdec_as_stack_peek (cx
, 2), NULL
, &pobj
);
883 if (SWFDEC_AS_VALUE_IS_STRING (*val
))
884 name
= SWFDEC_AS_VALUE_GET_STRING (*val
);
887 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_peek (cx
, 3));
888 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 2));
890 swfdec_as_stack_pop (cx
);
891 /* setup super to point to the right prototype */
892 if (obj
&& SWFDEC_IS_AS_SUPER (obj
->relay
)) {
893 super
= swfdec_as_super_resolve_property (SWFDEC_AS_SUPER (obj
->relay
), name
);
894 } else if (cx
->version
> 6 && pobj
!= obj
) {
897 super
= obj
->prototype
;
901 if (!swfdec_action_call (cx
, n_args
, super
)) {
902 SWFDEC_WARNING ("no function named \"%s\" on object %s", name
,
903 obj
&& obj
->relay
? G_OBJECT_TYPE_NAME(obj
->relay
) : "unknown");
908 swfdec_action_pop (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
910 swfdec_as_stack_pop (cx
);
914 swfdec_action_binary (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
918 r
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 1));
919 l
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 2));
921 case SWFDEC_AS_ACTION_ADD
:
924 case SWFDEC_AS_ACTION_SUBTRACT
:
927 case SWFDEC_AS_ACTION_MULTIPLY
:
930 case SWFDEC_AS_ACTION_DIVIDE
:
931 if (cx
->version
< 5) {
933 swfdec_as_stack_pop (cx
);
934 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR__ERROR_
);
950 g_assert_not_reached ();
953 swfdec_as_stack_pop (cx
);
954 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_number (cx
, l
);
958 swfdec_action_add2_to_primitive (SwfdecAsValue
*value
)
960 SwfdecAsObject
*object
;
963 if (!SWFDEC_AS_VALUE_IS_OBJECT (*value
))
965 object
= SWFDEC_AS_VALUE_GET_OBJECT (*value
);
967 if (SWFDEC_IS_AS_DATE (object
->relay
) && object
->context
->version
> 5)
968 name
= SWFDEC_AS_STR_toString
;
970 name
= SWFDEC_AS_STR_valueOf
;
971 swfdec_as_object_call (object
, name
, 0, NULL
, value
);
975 swfdec_action_add2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
977 SwfdecAsValue
*rval
, *lval
, rtmp
, ltmp
;
979 rval
= swfdec_as_stack_peek (cx
, 1);
980 lval
= swfdec_as_stack_peek (cx
, 2);
983 swfdec_action_add2_to_primitive (&rtmp
);
984 if (!SWFDEC_AS_VALUE_IS_OBJECT (rtmp
))
986 swfdec_action_add2_to_primitive (<mp
);
987 if (!SWFDEC_AS_VALUE_IS_OBJECT (ltmp
))
990 if (SWFDEC_AS_VALUE_IS_STRING (*lval
) || SWFDEC_AS_VALUE_IS_STRING (*rval
)) {
991 const char *lstr
, *rstr
;
992 lstr
= swfdec_as_value_to_string (cx
, *lval
);
993 rstr
= swfdec_as_value_to_string (cx
, *rval
);
994 lstr
= swfdec_as_str_concat (cx
, lstr
, rstr
);
995 swfdec_as_stack_pop (cx
);
996 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), lstr
);
999 d
= swfdec_as_value_to_number (cx
, *lval
);
1000 d2
= swfdec_as_value_to_number (cx
, *rval
);
1002 swfdec_as_stack_pop (cx
);
1003 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_number (cx
, d
);
1008 swfdec_action_new_comparison (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1010 SwfdecAsValue
*lval
, *rval
;
1013 rval
= swfdec_as_stack_peek (cx
, 1);
1014 lval
= swfdec_as_stack_peek (cx
, 2);
1016 /* swap if we do a greater comparison */
1017 if (action
== SWFDEC_AS_ACTION_GREATER
) {
1018 SwfdecAsValue
*tmp
= lval
;
1022 /* comparison with object is always false */
1023 *lval
= swfdec_as_value_to_primitive (*lval
);
1024 if (SWFDEC_AS_VALUE_IS_OBJECT (*lval
)) {
1025 swfdec_as_stack_pop (cx
);
1026 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
1029 /* same for the rval */
1030 *rval
= swfdec_as_value_to_primitive (*rval
);
1031 if (SWFDEC_AS_VALUE_IS_OBJECT (*rval
)) {
1032 swfdec_as_stack_pop (cx
);
1033 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), FALSE
);
1036 /* movieclips are not objects, but they evaluate to NaN, so we can handle them here */
1037 if (SWFDEC_AS_VALUE_IS_MOVIE (*rval
) ||
1038 SWFDEC_AS_VALUE_IS_MOVIE (*lval
)) {
1039 swfdec_as_stack_pop (cx
);
1040 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1043 /* if both are strings, compare strings */
1044 if (SWFDEC_AS_VALUE_IS_STRING (*rval
) &&
1045 SWFDEC_AS_VALUE_IS_STRING (*lval
)) {
1046 const char *ls
= SWFDEC_AS_VALUE_GET_STRING (*lval
);
1047 const char *rs
= SWFDEC_AS_VALUE_GET_STRING (*rval
);
1049 if (ls
== SWFDEC_AS_STR_EMPTY
) {
1050 cmp
= rs
== SWFDEC_AS_STR_EMPTY
? 0 : 1;
1051 } else if (rs
== SWFDEC_AS_STR_EMPTY
) {
1054 cmp
= strcmp (ls
, rs
);
1056 swfdec_as_stack_pop (cx
);
1057 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cmp
< 0);
1060 /* convert to numbers and compare those */
1061 l
= swfdec_as_value_to_number (cx
, *lval
);
1062 r
= swfdec_as_value_to_number (cx
, *rval
);
1063 swfdec_as_stack_pop (cx
);
1064 /* NaN results in undefined */
1065 if (isnan (l
) || isnan (r
)) {
1066 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1069 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), l
< r
);
1073 swfdec_action_not (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1075 if (cx
->version
<= 4) {
1076 double d
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 1));
1077 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_integer (cx
, d
== 0 ? 1 : 0);
1079 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1),
1080 !swfdec_as_value_to_boolean (cx
, *swfdec_as_stack_peek (cx
, 1)));
1085 swfdec_action_jump (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1090 SWFDEC_ERROR ("Jump action length invalid (is %u, should be 2)", len
);
1093 offset
= data
[0] | (data
[1] << 8);
1094 cx
->frame
->pc
+= 5 + (int) offset
;
1098 swfdec_action_if (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1101 SWFDEC_ERROR ("If action length invalid (is %u, should be 2)", len
);
1104 if (swfdec_as_value_to_boolean (cx
, *swfdec_as_stack_peek (cx
, 1))) {
1105 gint16 offset
= data
[0] | (data
[1] << 8);
1106 cx
->frame
->pc
+= 5 + (int) offset
;
1108 swfdec_as_stack_pop (cx
);
1112 swfdec_action_decrement (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1116 val
= swfdec_as_stack_peek (cx
, 1);
1117 *val
= swfdec_as_value_from_number (cx
, swfdec_as_value_to_number (cx
, *val
) - 1);
1121 swfdec_action_increment (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1125 val
= swfdec_as_stack_peek (cx
, 1);
1126 *val
= swfdec_as_value_from_number (cx
, swfdec_as_value_to_number (cx
, *val
) + 1);
1130 swfdec_action_get_url (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1136 swfdec_bits_init_data (&bits
, data
, len
);
1137 url
= swfdec_bits_get_string (&bits
, cx
->version
);
1138 t
= swfdec_bits_get_string (&bits
, cx
->version
);
1139 if (url
== NULL
|| t
== NULL
) {
1140 SWFDEC_ERROR ("not enough data in GetURL");
1145 target
= swfdec_as_context_give_string (cx
, t
);
1146 if (swfdec_bits_left (&bits
)) {
1147 SWFDEC_WARNING ("leftover bytes in GetURL action");
1149 if (!SWFDEC_IS_PLAYER (cx
)) {
1150 SWFDEC_ERROR ("GetURL without a SwfdecPlayer");
1152 swfdec_resource_load (SWFDEC_PLAYER (cx
), target
, url
, NULL
);
1158 swfdec_as_interpret_load_variables_on_finish (SwfdecPlayer
*player
,
1159 const SwfdecAsValue
*val
, const char *text
)
1161 SwfdecMovie
*movie
= SWFDEC_AS_VALUE_GET_MOVIE (*val
);
1167 swfdec_as_object_decode (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
)), text
);
1169 // only call onData for sprite movies
1170 swfdec_actor_queue_script (SWFDEC_ACTOR (movie
), SWFDEC_EVENT_DATA
);
1174 swfdec_as_interpret_encode_variables_foreach (SwfdecAsObject
*object
,
1175 const char *variable
, SwfdecAsValue
*value
, guint flags
, gpointer data
)
1177 SwfdecAsContext
*context
;
1178 GString
*variables
= data
;
1181 context
= object
->context
;
1182 // FIXME: check propflags?
1184 if (variables
->len
> 0)
1185 g_string_append_c (variables
, '&');
1187 escaped
= swfdec_as_string_escape (context
, variable
);
1188 g_string_append (variables
, escaped
);
1191 g_string_append_c (variables
, '=');
1193 escaped
= swfdec_as_string_escape (context
,
1194 swfdec_as_value_to_string (context
, *value
));
1195 g_string_append (variables
, escaped
);
1202 swfdec_as_interpret_encode_variables (SwfdecAsObject
*object
)
1204 GString
*variables
= g_string_new ("");
1206 SWFDEC_FIXME ("Encoding variables for getURL2 shouldn't include child movies");
1207 swfdec_as_object_foreach (object
,
1208 swfdec_as_interpret_encode_variables_foreach
, variables
);
1210 return g_string_free (variables
, FALSE
);
1214 swfdec_action_get_url2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1216 const char *target
, *url
;
1217 guint method
, internal
, variables
;
1218 SwfdecBuffer
*buffer
;
1222 SWFDEC_ERROR ("GetURL2 requires 1 byte of data, not %u", len
);
1226 method
= data
[0] & 3;
1228 SWFDEC_ERROR ("GetURL method 3 invalid");
1231 internal
= data
[0] & 64;
1232 variables
= data
[0] & 128;
1234 url
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
1237 if (method
== 1 || method
== 2) {
1241 movie
= swfdec_as_frame_get_target (cx
->frame
);
1242 if (movie
== NULL
) {
1243 SWFDEC_FIXME ("no target, what do we encode now?");
1246 text
= swfdec_as_interpret_encode_variables (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
)));
1248 url
= swfdec_as_context_give_string (cx
, g_strjoin (NULL
, url
,
1249 strchr (url
, '?') == NULL
? "?" : "&", text
, NULL
));
1251 // don't send the nul-byte
1252 buffer
= swfdec_buffer_new_for_data (g_memdup (text
, strlen (text
)),
1258 if (!SWFDEC_IS_PLAYER (cx
)) {
1259 SWFDEC_ERROR ("GetURL2 action requires a SwfdecPlayer");
1260 } else if (variables
) {
1263 target
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
1264 movie
= swfdec_player_get_movie_from_string (SWFDEC_PLAYER (cx
), target
);
1265 if (movie
!= NULL
) {
1266 SWFDEC_AS_VALUE_SET_MOVIE (&val
, movie
);
1267 swfdec_load_object_create (SWFDEC_PLAYER (cx
), &val
, url
, buffer
, 0,
1268 NULL
, NULL
, NULL
, swfdec_as_interpret_load_variables_on_finish
);
1270 } else if (internal
) {
1271 swfdec_resource_load_movie (SWFDEC_PLAYER (cx
), swfdec_as_stack_peek (cx
, 1),
1274 target
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
1275 swfdec_resource_load (SWFDEC_PLAYER (cx
), target
, url
, buffer
);
1278 swfdec_as_stack_pop_n (cx
, 2);
1282 swfdec_action_string_add (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1284 const char *lval
, *rval
;
1286 rval
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
1287 lval
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
1288 lval
= swfdec_as_str_concat (cx
, lval
, rval
);
1289 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 2), lval
);
1290 swfdec_as_stack_pop (cx
);
1294 swfdec_action_push_duplicate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1296 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
1298 *swfdec_as_stack_push (cx
) = *val
;
1302 swfdec_action_random_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1307 val
= swfdec_as_stack_peek (cx
, 1);
1308 max
= swfdec_as_value_to_integer (cx
, *val
);
1311 *val
= swfdec_as_value_from_number (cx
, 0);
1313 *val
= swfdec_as_value_from_number (cx
, g_rand_int_range (cx
->rand
, 0, max
));
1317 swfdec_action_old_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1322 l
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 2));
1323 r
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 1));
1325 case SWFDEC_AS_ACTION_EQUALS
:
1328 case SWFDEC_AS_ACTION_LESS
:
1332 g_assert_not_reached ();
1335 swfdec_as_stack_pop (cx
);
1336 if (cx
->version
< 5) {
1337 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_integer (cx
, cond
? 1 : 0);
1339 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1344 swfdec_action_string_extract (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1349 n
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1));
1350 start
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 2));
1351 s
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 3));
1352 swfdec_as_stack_pop_n (cx
, 2);
1353 left
= g_utf8_strlen (s
, -1);
1355 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1), SWFDEC_AS_STR_EMPTY
);
1357 } else if (start
< 2) {
1363 if (n
< 0 || n
> left
)
1366 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
1367 swfdec_as_str_sub (cx
, s
, start
, n
));
1371 swfdec_action_string_length (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1376 v
= swfdec_as_stack_peek (cx
, 1);
1377 s
= swfdec_as_value_to_string (cx
, *v
);
1378 *v
= swfdec_as_value_from_integer (cx
, g_utf8_strlen (s
, -1));
1382 swfdec_action_string_compare (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1387 r
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
1388 l
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
1390 case SWFDEC_AS_ACTION_STRING_EQUALS
:
1393 case SWFDEC_AS_ACTION_STRING_LESS
:
1394 cond
= strcmp (l
, r
) < 0;
1396 case SWFDEC_AS_ACTION_STRING_GREATER
:
1397 cond
= strcmp (l
, r
) > 0;
1401 g_assert_not_reached ();
1404 swfdec_as_stack_pop (cx
);
1405 if (cx
->version
< 5) {
1406 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_integer (cx
, cond
? 1 : 0);
1408 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1413 swfdec_action_equals2_5 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1415 SwfdecAsValue
*rval
, *lval
;
1416 SwfdecAsValue rtmp
, ltmp
;
1417 SwfdecAsValueType ltype
, rtype
;
1421 rval
= swfdec_as_stack_peek (cx
, 1);
1422 lval
= swfdec_as_stack_peek (cx
, 2);
1423 rtmp
= swfdec_as_value_to_primitive (*rval
);
1424 ltmp
= swfdec_as_value_to_primitive (*lval
);
1425 ltype
= SWFDEC_AS_VALUE_GET_TYPE (ltmp
);
1426 rtype
= SWFDEC_AS_VALUE_GET_TYPE (rtmp
);
1428 if (SWFDEC_AS_VALUE_IS_COMPOSITE (ltmp
) && SWFDEC_AS_VALUE_IS_COMPOSITE (rtmp
)) {
1429 /* get movies compared */
1430 if (ltype
== SWFDEC_AS_TYPE_MOVIE
) {
1431 if (rtype
== SWFDEC_AS_TYPE_MOVIE
) {
1434 *rval
= swfdec_as_value_to_primitive (*rval
);
1436 cond
= SWFDEC_AS_VALUE_IS_MOVIE (*rval
) &&
1437 SWFDEC_AS_VALUE_GET_MOVIE (ltmp
) == SWFDEC_AS_VALUE_GET_MOVIE (*rval
);
1440 if (rtype
== SWFDEC_AS_TYPE_MOVIE
) {
1441 *lval
= swfdec_as_value_to_primitive (*lval
);
1442 cond
= SWFDEC_AS_VALUE_IS_MOVIE (*lval
) &&
1443 SWFDEC_AS_VALUE_GET_MOVIE (rtmp
) == SWFDEC_AS_VALUE_GET_MOVIE (*lval
);
1447 cond
= SWFDEC_AS_VALUE_GET_OBJECT (*lval
) == SWFDEC_AS_VALUE_GET_OBJECT (*rval
);
1451 /* compare strings */
1452 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1453 cond
= SWFDEC_AS_VALUE_GET_STRING (ltmp
) == SWFDEC_AS_VALUE_GET_STRING (rtmp
);
1457 /* convert to numbers */
1458 if (SWFDEC_AS_VALUE_IS_OBJECT (ltmp
)) {
1459 l
= swfdec_as_value_to_number (cx
, *lval
);
1461 l
= swfdec_as_value_to_number (cx
, ltmp
);
1463 if (SWFDEC_AS_VALUE_IS_OBJECT (rtmp
)) {
1464 r
= swfdec_as_value_to_number (cx
, *rval
);
1466 r
= swfdec_as_value_to_number (cx
, rtmp
);
1469 /* get rid of undefined and null */
1470 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1471 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1478 /* else compare as numbers */
1479 if (isnan (l
) && isnan (r
)) {
1480 cond
= (ltype
== SWFDEC_AS_TYPE_NUMBER
&& ltmp
== rtmp
);
1486 swfdec_as_stack_pop (cx
);
1487 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1491 swfdec_action_equals2_6 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1493 SwfdecAsValue
*rval
, *lval
;
1494 SwfdecAsValueType ltype
, rtype
;
1498 rval
= swfdec_as_stack_peek (cx
, 1);
1499 lval
= swfdec_as_stack_peek (cx
, 2);
1500 /* check objects before anything else */
1501 if (SWFDEC_AS_VALUE_IS_OBJECT (*lval
) && SWFDEC_AS_VALUE_IS_OBJECT (*rval
)) {
1502 cond
= SWFDEC_AS_VALUE_GET_OBJECT (*lval
) == SWFDEC_AS_VALUE_GET_OBJECT (*rval
);
1505 *lval
= swfdec_as_value_to_primitive (*lval
);
1506 *rval
= swfdec_as_value_to_primitive (*rval
);
1508 /* check if we have equal movieclips */
1509 if (SWFDEC_AS_VALUE_IS_MOVIE (*lval
)) {
1510 cond
= SWFDEC_AS_VALUE_IS_MOVIE (*rval
) &&
1511 SWFDEC_AS_VALUE_GET_MOVIE (*lval
) == SWFDEC_AS_VALUE_GET_MOVIE (*rval
);
1515 /* now all composites compare false */
1516 if (SWFDEC_AS_VALUE_IS_COMPOSITE (*lval
) ||
1517 SWFDEC_AS_VALUE_IS_COMPOSITE (*rval
)) {
1522 ltype
= SWFDEC_AS_VALUE_GET_TYPE (*lval
);
1523 rtype
= SWFDEC_AS_VALUE_GET_TYPE (*rval
);
1525 /* get rid of undefined and null */
1526 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1527 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1534 /* compare strings */
1535 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1536 cond
= SWFDEC_AS_VALUE_GET_STRING (*lval
) == SWFDEC_AS_VALUE_GET_STRING (*rval
);
1540 /* else compare as numbers */
1541 l
= swfdec_as_value_to_number (cx
, *lval
);
1542 r
= swfdec_as_value_to_number (cx
, *rval
);
1544 if (isnan (l
) && isnan (r
)) {
1545 cond
= (ltype
== SWFDEC_AS_TYPE_NUMBER
&& *lval
== *rval
);
1551 swfdec_as_stack_pop (cx
);
1552 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1556 swfdec_action_equals2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1558 if (cx
->version
<= 5) {
1559 swfdec_action_equals2_5 (cx
, action
, data
, len
);
1561 swfdec_action_equals2_6 (cx
, action
, data
, len
);
1566 swfdec_action_strict_equals (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1568 SwfdecAsValue
*rval
, *lval
;
1571 rval
= swfdec_as_stack_peek (cx
, 1);
1572 lval
= swfdec_as_stack_peek (cx
, 2);
1574 if (SWFDEC_AS_VALUE_GET_TYPE (*rval
) != SWFDEC_AS_VALUE_GET_TYPE (*lval
)) {
1577 switch (SWFDEC_AS_VALUE_GET_TYPE (*rval
)) {
1578 case SWFDEC_AS_TYPE_UNDEFINED
:
1579 case SWFDEC_AS_TYPE_NULL
:
1582 case SWFDEC_AS_TYPE_BOOLEAN
:
1583 cond
= SWFDEC_AS_VALUE_GET_BOOLEAN (*rval
) == SWFDEC_AS_VALUE_GET_BOOLEAN (*lval
);
1585 case SWFDEC_AS_TYPE_NUMBER
:
1588 r
= SWFDEC_AS_VALUE_GET_NUMBER (*rval
);
1589 l
= SWFDEC_AS_VALUE_GET_NUMBER (*lval
);
1590 cond
= (l
== r
) || (isnan (l
) && isnan (r
));
1593 case SWFDEC_AS_TYPE_STRING
:
1594 cond
= SWFDEC_AS_VALUE_GET_STRING (*rval
) == SWFDEC_AS_VALUE_GET_STRING (*lval
);
1596 case SWFDEC_AS_TYPE_OBJECT
:
1597 cond
= SWFDEC_AS_VALUE_GET_OBJECT (*lval
) == SWFDEC_AS_VALUE_GET_OBJECT (*rval
);
1599 case SWFDEC_AS_TYPE_MOVIE
:
1600 cond
= SWFDEC_AS_VALUE_GET_MOVIE (*lval
) == SWFDEC_AS_VALUE_GET_MOVIE (*rval
);
1602 case SWFDEC_AS_TYPE_INT
:
1604 g_assert_not_reached ();
1609 swfdec_as_stack_pop (cx
);
1610 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1614 swfdec_action_do_set_target (SwfdecAsContext
*cx
, const char *target
, const char *end
)
1616 swfdec_as_frame_set_target (cx
->frame
, NULL
);
1618 if (target
!= end
) {
1619 SwfdecAsObject
*o
= swfdec_action_lookup_object (cx
, NULL
, target
, end
);
1621 SWFDEC_WARNING ("target \"%s\" is not an object", target
);
1622 } else if (!o
->movie
) {
1623 SWFDEC_FIXME ("target \"%s\" is not a movie, something weird is supposed to happen now", target
);
1625 swfdec_as_frame_set_target (cx
->frame
, SWFDEC_MOVIE (o
->relay
));
1631 swfdec_action_set_target (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1635 end
= memchr (data
, 0, len
);
1637 SWFDEC_ERROR ("SetTarget action does not specify a string");
1640 swfdec_action_do_set_target (cx
, (const char *) data
, end
);
1644 swfdec_action_set_target2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1648 s
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
1649 swfdec_action_do_set_target (cx
, s
, s
+ strlen (s
));
1650 swfdec_as_stack_pop (cx
);
1654 swfdec_action_start_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1656 SwfdecRect rect
, *rectp
= NULL
;
1659 guint stack_size
= 3;
1661 swfdec_as_stack_ensure_size (cx
, 3);
1662 center
= swfdec_as_value_to_boolean (cx
, *swfdec_as_stack_peek (cx
, 2));
1663 if (swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 3))) {
1664 swfdec_as_stack_ensure_size (cx
, 7);
1665 rect
.x0
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 7));
1666 rect
.y0
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 6));
1667 rect
.x1
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 5));
1668 rect
.y1
= swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 4));
1669 swfdec_rect_scale (&rect
, &rect
, SWFDEC_TWIPS_SCALE_FACTOR
);
1673 if (!SWFDEC_IS_PLAYER (cx
)) {
1674 SWFDEC_ERROR ("called startDrag on a non-SwfdecPlayer");
1676 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
), swfdec_as_stack_peek (cx
, 1));
1677 if (SWFDEC_IS_ACTOR (movie
)) {
1678 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), SWFDEC_ACTOR (movie
), center
, rectp
);
1680 SWFDEC_ERROR ("startDrag on something not an Actor");
1683 swfdec_as_stack_pop_n (cx
, stack_size
);
1687 swfdec_action_end_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1689 if (SWFDEC_IS_PLAYER (cx
)) {
1690 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), NULL
, FALSE
, NULL
);
1692 SWFDEC_WARNING ("can't end a drag on non-players");
1697 swfdec_action_stop_sounds (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1699 if (SWFDEC_IS_PLAYER (cx
)) {
1700 swfdec_player_stop_all_sounds (SWFDEC_PLAYER (cx
));
1705 swfdec_action_new_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1707 SwfdecAsValue
*constructor
;
1708 SwfdecAsFunction
*fun
;
1711 swfdec_as_stack_ensure_size (cx
, 2);
1712 swfdec_action_get_variable (cx
, action
, data
, len
);
1713 constructor
= swfdec_as_stack_peek (cx
, 1);
1714 n_args
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 2));
1715 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 2, n_args
);
1716 if (!SWFDEC_AS_VALUE_IS_OBJECT (*constructor
) ||
1717 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (*constructor
)->relay
)) {
1718 SWFDEC_WARNING ("not a constructor");
1722 swfdec_as_stack_pop_n (cx
, 2);
1723 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1727 swfdec_as_stack_pop_n (cx
, n_args
+ 1);
1728 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1732 swfdec_action_new_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1734 SwfdecAsValue
*constructor
;
1735 SwfdecAsFunction
*fun
;
1739 swfdec_as_stack_ensure_size (cx
, 3);
1740 name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
1742 constructor
= swfdec_as_stack_peek (cx
, 2);
1743 n_args
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 3));
1744 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 3, n_args
);
1745 if (name
== SWFDEC_AS_STR_EMPTY
||
1746 SWFDEC_AS_VALUE_IS_UNDEFINED (*swfdec_as_stack_peek (cx
, 1))) {
1748 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (*constructor
)) {
1749 SWFDEC_WARNING ("NewMethod called without an object to get variable %s from", name
);
1752 swfdec_as_object_get_variable (SWFDEC_AS_VALUE_GET_COMPOSITE (*constructor
),
1755 if (!SWFDEC_AS_VALUE_IS_OBJECT (*constructor
) ||
1756 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (*constructor
)->relay
)) {
1757 SWFDEC_WARNING ("%s is not a constructor", name
);
1761 swfdec_as_stack_pop_n (cx
, 3);
1762 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1766 swfdec_as_stack_pop_n (cx
, n_args
+ 2);
1767 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1771 swfdec_action_init_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1773 SwfdecAsObject
*object
;
1774 guint i
, n_args
, size
;
1776 n_args
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1));
1777 swfdec_as_stack_pop (cx
);
1778 if (n_args
* 2 > swfdec_as_stack_get_size (cx
)) {
1779 size
= swfdec_as_stack_get_size (cx
);
1780 SWFDEC_FIXME ("InitObject action with too small stack, help!");
1787 object
= swfdec_as_object_new (cx
, NULL
);
1788 swfdec_as_object_set_constructor_by_name (object
, SWFDEC_AS_STR_Object
, NULL
);
1789 for (i
= 0; i
< n_args
; i
++) {
1790 const char *s
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
1791 swfdec_as_object_set_variable (object
, s
, swfdec_as_stack_peek (cx
, 1));
1792 swfdec_as_stack_pop_n (cx
, 2);
1794 swfdec_as_stack_pop_n (cx
, size
);
1795 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
1799 swfdec_action_init_array (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1802 SwfdecAsObject
*array
;
1804 swfdec_as_stack_ensure_size (cx
, 1);
1805 n
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1));
1806 swfdec_as_stack_pop (cx
);
1807 array
= swfdec_as_array_new (cx
);
1808 /* NB: we can't increase the stack here, as the number can easily be MAXINT */
1809 for (i
= 0; i
< n
&& swfdec_as_stack_get_size (cx
) > 0; i
++) {
1810 swfdec_as_stack_ensure_size (cx
, 1);
1811 swfdec_as_array_push (array
, swfdec_as_stack_pop (cx
));
1815 val
= swfdec_as_value_from_integer (cx
, n
);
1816 swfdec_as_object_set_variable (array
, SWFDEC_AS_STR_length
, &val
);
1818 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), array
);
1822 swfdec_action_define_function (SwfdecAsContext
*cx
, guint action
,
1823 const guint8
*data
, guint len
)
1825 char *function_name
;
1826 const char *name
= NULL
;
1827 guint i
, n_args
, size
, n_registers
;
1829 SwfdecBuffer
*buffer
;
1830 SwfdecAsFunction
*fun
;
1831 SwfdecAsFrame
*frame
;
1832 SwfdecScript
*script
;
1834 SwfdecScriptArgument
*args
;
1835 gboolean v2
= (action
== 0x8e);
1838 swfdec_bits_init_data (&bits
, data
, len
);
1839 function_name
= swfdec_bits_get_string (&bits
, cx
->version
);
1840 if (function_name
== NULL
) {
1841 SWFDEC_ERROR ("could not parse function name");
1844 n_args
= swfdec_bits_get_u16 (&bits
);
1846 n_registers
= swfdec_bits_get_u8 (&bits
);
1847 if (n_registers
== 0)
1849 flags
= swfdec_bits_get_u16 (&bits
);
1854 args
= g_new0 (SwfdecScriptArgument
, n_args
);
1855 for (i
= 0; i
< n_args
&& swfdec_bits_left (&bits
); i
++) {
1857 args
[i
].preload
= swfdec_bits_get_u8 (&bits
);
1858 if (args
[i
].preload
&& args
[i
].preload
>= n_registers
) {
1859 SWFDEC_ERROR ("argument %u cannot be preloaded into register %u out of %u",
1860 i
, args
[i
].preload
, n_registers
);
1861 /* FIXME: figure out correct error handling here */
1862 args
[i
].preload
= 0;
1865 args
[i
].name
= swfdec_bits_get_string (&bits
, cx
->version
);
1866 if (args
[i
].name
== NULL
|| args
[i
].name
== '\0') {
1867 SWFDEC_ERROR ("empty argument name not allowed");
1871 /* FIXME: check duplicate arguments */
1876 size
= swfdec_bits_get_u16 (&bits
);
1877 /* check the script can be created */
1878 if (frame
->script
->buffer
->data
+ frame
->script
->buffer
->length
< frame
->pc
+ 3 + len
+ size
) {
1879 SWFDEC_ERROR ("size of function is too big");
1881 g_free (function_name
);
1884 /* create the script */
1885 buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
1886 frame
->pc
+ 3 + len
- frame
->script
->buffer
->data
, size
);
1887 swfdec_bits_init (&bits
, buffer
);
1888 if (*function_name
) {
1889 name
= function_name
;
1890 } else if (swfdec_as_stack_get_size (cx
) > 0) {
1891 /* This is kind of a hack that uses a feature of the Adobe compiler:
1892 * foo = function () {} is compiled as these actions:
1893 * Push "foo", DefineFunction, SetVariable/SetMember
1894 * With this knowledge we can inspect the topmost stack member, since
1895 * it will contain the name this function will soon be assigned to.
1897 if (SWFDEC_AS_VALUE_IS_STRING (*swfdec_as_stack_peek (cx
, 1)))
1898 name
= SWFDEC_AS_VALUE_GET_STRING (*swfdec_as_stack_peek (cx
, 1));
1901 name
= "unnamed_function";
1902 script
= swfdec_script_new_from_bits (&bits
, name
, cx
->version
);
1903 swfdec_buffer_unref (buffer
);
1904 if (script
== NULL
) {
1905 SWFDEC_ERROR ("failed to create script");
1907 g_free (function_name
);
1910 if (frame
->constant_pool
)
1911 script
->constant_pool
= swfdec_buffer_ref (swfdec_constant_pool_get_buffer (frame
->constant_pool
));
1912 script
->flags
= flags
;
1913 script
->n_registers
= n_registers
;
1914 script
->n_arguments
= n_args
;
1915 script
->arguments
= args
;
1916 /* see function-scope tests */
1917 if (cx
->version
> 5) {
1918 /* FIXME: or original target? */
1919 fun
= swfdec_as_script_function_new (cx
, frame
->original_target
, frame
->scope_chain
, script
);
1921 fun
= swfdec_as_script_function_new (cx
, frame
->original_target
, NULL
, script
);
1923 /* This is a hack that should only trigger for functions defined in the init scripts.
1924 * It is supposed to ensure that those functions inherit their target when being
1925 * called instead of when being defined */
1926 if (!SWFDEC_IS_MOVIE (frame
->original_target
))
1927 SWFDEC_AS_SCRIPT_FUNCTION (fun
)->target
= NULL
;
1928 /* attach the function */
1929 if (*function_name
== '\0') {
1930 swfdec_as_stack_ensure_free (cx
, 1);
1931 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
),
1932 swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (fun
)));
1934 SwfdecAsValue funval
;
1935 SwfdecMovie
*target
= frame
->original_target
;
1937 name
= swfdec_as_context_get_string (cx
, function_name
);
1938 SWFDEC_AS_VALUE_SET_OBJECT (&funval
, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (fun
)));
1939 swfdec_as_object_set_variable (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target
)),
1944 /* update current context */
1945 frame
->pc
+= 3 + len
+ size
;
1946 g_free (function_name
);
1950 swfdec_action_bitwise (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1954 a
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1));
1955 b
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 2));
1968 g_assert_not_reached ();
1972 swfdec_as_stack_pop (cx
);
1973 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_integer (cx
, a
);
1977 swfdec_action_shift (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1981 amount
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1));
1983 value
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 2));
1987 value
= value
<< amount
;
1990 value
= ((gint
) value
) >> amount
;
1993 value
= ((guint
) value
) >> amount
;
1996 g_assert_not_reached ();
1999 swfdec_as_stack_pop (cx
);
2000 *swfdec_as_stack_peek (cx
, 1) = swfdec_as_value_from_integer (cx
, value
);
2004 swfdec_action_to_integer (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2006 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2008 *val
= swfdec_as_value_from_integer (cx
, swfdec_as_value_to_integer (cx
, *val
));
2012 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_MOVIE (*val
)) {
2020 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2023 s
= swfdec_movie_get_path (SWFDEC_AS_VALUE_GET_MOVIE (*val
), TRUE
);
2024 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_give_string (cx
, s
));
2028 swfdec_action_define_local (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2032 name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
2033 swfdec_as_frame_set_variable (cx
, cx
->frame
, name
, swfdec_as_stack_peek (cx
, 1),
2035 swfdec_as_stack_pop_n (cx
, 2);
2039 swfdec_action_define_local2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2041 SwfdecAsValue val
= { 0, };
2044 name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
2045 swfdec_as_frame_set_variable (cx
, cx
->frame
, name
, &val
, FALSE
, TRUE
);
2046 swfdec_as_stack_pop (cx
);
2050 swfdec_action_end (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2052 swfdec_as_context_return (cx
, NULL
);
2056 swfdec_action_return (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2058 swfdec_as_context_return (cx
, swfdec_as_stack_pop (cx
));
2062 swfdec_action_delete (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2066 gboolean success
= FALSE
;
2068 name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 1));
2069 val
= swfdec_as_stack_peek (cx
, 2);
2070 if (SWFDEC_AS_VALUE_IS_COMPOSITE (*val
)) {
2071 SwfdecAsObject
*o
= SWFDEC_AS_VALUE_GET_COMPOSITE (*val
);
2073 success
= swfdec_as_object_delete_variable (o
, 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
, 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_stack_peek (cx
, 1) = swfdec_as_value_from_number (cx
, 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_stack_peek (cx
, 1) = swfdec_as_value_from_number (cx
,
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_pop (cx
);
2154 switch (SWFDEC_AS_VALUE_GET_TYPE (val
)) {
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_AS_FUNCTION (obj
->relay
)) {
2174 type
= SWFDEC_AS_STR_function
;
2176 type
= SWFDEC_AS_STR_object
;
2180 case SWFDEC_AS_TYPE_MOVIE
:
2182 SwfdecMovie
*movie
= SWFDEC_AS_VALUE_GET_MOVIE (val
);
2183 if (SWFDEC_IS_TEXT_FIELD_MOVIE (movie
) &&
2184 movie
->state
== SWFDEC_MOVIE_STATE_RUNNING
) {
2185 type
= SWFDEC_AS_STR_object
;
2187 type
= SWFDEC_AS_STR_movieclip
;
2191 case SWFDEC_AS_TYPE_INT
:
2193 g_assert_not_reached ();
2194 type
= SWFDEC_AS_STR_EMPTY
;
2197 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
), type
);
2201 swfdec_action_get_time (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2206 swfdec_as_context_get_time (cx
, &tv
);
2207 /* we assume here that swfdec_as_context_get_time always returns a tv > start_time */
2208 diff
= tv
.tv_sec
- cx
->start_time
.tv_sec
;
2210 diff
+= (tv
.tv_usec
- cx
->start_time
.tv_usec
) / 1000;
2212 *swfdec_as_stack_push (cx
) = swfdec_as_value_from_number (cx
, diff
);
2216 swfdec_action_is_instance_of (SwfdecAsObject
*object
,
2217 SwfdecAsObject
*constructor
)
2220 SwfdecAsObject
*class, *prototype
;
2223 g_return_val_if_fail (object
!= NULL
, FALSE
);
2224 g_return_val_if_fail (constructor
!= NULL
, FALSE
);
2226 // FIXME: propflag tests are wrong, and we shouldn't get __proto__.prototype
2227 swfdec_as_object_get_variable (constructor
, SWFDEC_AS_STR_prototype
, &val
);
2228 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
))
2230 prototype
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2233 while ((class = swfdec_as_object_get_prototype (class)) != NULL
) {
2234 if (class == prototype
)
2236 for (iter
= class->interfaces
; iter
!= NULL
; iter
= iter
->next
) {
2237 if (iter
->data
== prototype
)
2246 swfdec_action_instance_of (SwfdecAsContext
*cx
, guint action
,
2247 const guint8
*data
, guint len
)
2250 SwfdecAsObject
*object
, *constructor
;
2252 val
= swfdec_as_stack_pop (cx
);
2253 if (SWFDEC_AS_VALUE_IS_OBJECT (*val
)) {
2254 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (*val
);
2259 val
= swfdec_as_stack_pop (cx
);
2260 if (SWFDEC_AS_VALUE_IS_COMPOSITE (*val
)) {
2261 object
= SWFDEC_AS_VALUE_GET_COMPOSITE (*val
);
2267 if (object
== NULL
|| constructor
== NULL
) {
2268 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
), FALSE
);
2272 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
2273 swfdec_action_is_instance_of (object
, constructor
));
2277 swfdec_action_cast (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2281 SwfdecAsObject
*object
, *constructor
;
2283 val
= swfdec_as_stack_pop (cx
);
2284 if (SWFDEC_AS_VALUE_IS_COMPOSITE (*val
)) {
2285 object
= SWFDEC_AS_VALUE_GET_COMPOSITE (*val
);
2290 val
= swfdec_as_stack_pop (cx
);
2291 if (SWFDEC_AS_VALUE_IS_OBJECT (*val
)) {
2292 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (*val
);
2297 if (object
== NULL
|| constructor
== NULL
) {
2298 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2302 if (swfdec_action_is_instance_of (object
, constructor
)) {
2303 SWFDEC_AS_VALUE_SET_COMPOSITE (swfdec_as_stack_push (cx
), object
);
2305 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2310 swfdec_action_implements (SwfdecAsContext
*cx
, guint action
,
2311 const guint8
*data
, guint len
)
2313 SwfdecAsValue
*val
, *argv
;
2314 SwfdecAsObject
*object
, *proto
;
2317 swfdec_as_stack_ensure_size (cx
, 2);
2319 val
= swfdec_as_stack_pop (cx
);
2320 if (SWFDEC_AS_VALUE_IS_COMPOSITE (*val
)) {
2321 object
= SWFDEC_AS_VALUE_GET_COMPOSITE (*val
);
2322 swfdec_as_object_get_variable (object
, SWFDEC_AS_STR_prototype
, val
);
2323 if (SWFDEC_AS_VALUE_IS_OBJECT (*val
)) {
2324 proto
= SWFDEC_AS_VALUE_GET_OBJECT (*val
);
2333 val
= swfdec_as_stack_pop (cx
);
2334 argc
= swfdec_as_value_to_integer (cx
, *val
);
2337 swfdec_as_stack_ensure_size (cx
, argc
);
2338 argv
= swfdec_as_stack_pop_n (cx
, argc
);
2346 for (i
= 0; i
< argc
; i
++) {
2347 swfdec_as_value_get_variable (cx
, &argv
[i
], 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
)->relay
)) {
2366 SWFDEC_ERROR ("superclass is not a function");
2369 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (*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_COMPOSITE (*subclass
),
2382 SWFDEC_AS_STR_prototype
, &proto
);
2384 swfdec_as_stack_pop_n (cx
, 2);
2388 swfdec_action_do_enumerate (SwfdecAsContext
*cx
, SwfdecAsObject
*object
)
2391 GSList
*walk
, *list
;
2393 list
= swfdec_as_object_enumerate (object
);
2395 for (walk
= list
; walk
; walk
= walk
->next
) {
2396 /* 8 is an arbitrary value */
2398 swfdec_as_stack_ensure_free (cx
, 8);
2402 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
), walk
->data
);
2404 g_slist_free (list
);
2408 swfdec_action_enumerate2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2411 SwfdecAsObject
*obj
;
2413 val
= swfdec_as_stack_peek (cx
, 1);
2414 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (*val
) ||
2415 (obj
= SWFDEC_AS_VALUE_GET_COMPOSITE (*val
)) == NULL
) {
2416 SWFDEC_WARNING ("Enumerate called without an object");
2417 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2420 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2421 swfdec_action_do_enumerate (cx
, obj
);
2425 swfdec_action_enumerate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2427 /* FIXME: make this proper functions */
2428 swfdec_action_get_variable (cx
, action
, data
, len
);
2429 swfdec_action_enumerate2 (cx
, action
, data
, len
);
2433 swfdec_action_logical (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2437 if (cx
->version
<= 4) {
2438 l
= (swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 1)) != 0);
2439 // don't call second parameter if not necessary
2440 if ((action
== SWFDEC_AS_ACTION_AND
&& !l
) ||
2441 (action
!= SWFDEC_AS_ACTION_AND
&& l
)) {
2442 r
= (swfdec_as_value_to_number (cx
, *swfdec_as_stack_peek (cx
, 2)) != 0);
2447 l
= swfdec_as_value_to_boolean (cx
, *swfdec_as_stack_peek (cx
, 1));
2448 r
= swfdec_as_value_to_boolean (cx
, *swfdec_as_stack_peek (cx
, 2));
2451 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 2),
2452 (action
== SWFDEC_AS_ACTION_AND
) ? (l
&& r
) : (l
|| r
));
2453 swfdec_as_stack_pop (cx
);
2457 swfdec_action_char_to_ascii (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2459 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2460 const char *s
= swfdec_as_value_to_string (cx
, *val
);
2462 if (cx
->version
<= 5) {
2463 char *ascii
= g_convert (s
, -1, "LATIN1", "UTF-8", NULL
, NULL
, NULL
);
2465 if (ascii
== NULL
) {
2466 /* This can happen if a Flash 5 movie gets loaded into a Flash 7 movie */
2467 SWFDEC_FIXME ("Someone threw unconvertible text %s at Flash <= 5", s
);
2468 *val
= swfdec_as_value_from_integer (cx
, 0); /* FIXME: what to return??? */
2470 *val
= swfdec_as_value_from_integer (cx
, (guchar
) ascii
[0]);
2474 gunichar
*uni
= g_utf8_to_ucs4_fast (s
, -1, NULL
);
2477 /* This should never happen, everything is valid UTF-8 in here */
2478 g_warning ("conversion of character %s failed", s
);
2479 *val
= swfdec_as_value_from_integer (cx
, 0);
2481 *val
= swfdec_as_value_from_integer (cx
, uni
[0]);
2488 swfdec_action_ascii_to_char (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2490 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2492 if (cx
->version
<= 5) {
2497 if (action
== SWFDEC_AS_ACTION_ASCII_TO_CHAR
) {
2498 s
[0] = ((guint
) swfdec_as_value_to_integer (cx
, *val
)) % 256;
2501 g_assert (action
== SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
);
2503 i
= ((guint
) swfdec_as_value_to_integer (cx
, *val
));
2514 utf8
= g_convert (s
, -1, "UTF-8", "LATIN1", NULL
, NULL
, NULL
);
2516 g_warning ("conversion of character %u failed", (guint
) s
[0]);
2517 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2519 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, utf8
));
2524 gunichar c
= ((guint
) swfdec_as_value_to_integer (cx
, *val
)) % 65536;
2526 s
= g_ucs4_to_utf8 (&c
, 1, NULL
, NULL
, NULL
);
2528 g_warning ("conversion of character %u failed", (guint
) c
);
2529 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2531 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, s
));
2538 swfdec_action_throw (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2541 swfdec_as_context_throw (cx
, swfdec_as_stack_pop (cx
));
2545 const guint8
* catch_start
;
2546 const guint8
* finally_start
;
2550 gboolean use_register
;
2552 guint register_number
;
2553 char * variable_name
;
2556 SwfdecAsObject
* scope_object
;
2560 swfdec_action_try_data_free (gpointer data
)
2562 TryData
*try_data
= data
;
2564 g_return_if_fail (try_data
!= NULL
);
2566 if (!try_data
->use_register
)
2567 g_free (try_data
->variable_name
);
2572 swfdec_action_try_end_finally (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2574 SwfdecAsValue
*exception_value
= data
;
2577 // finally has ended and we had exception stored, throw it
2578 if (!cx
->exception
&& cx
->frame
== frame
)
2579 swfdec_as_context_throw (cx
, exception_value
);
2585 swfdec_action_try_end_catch (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2587 TryData
*try_data
= data
;
2588 SwfdecAsValue
*exception_value
, val
;
2590 g_return_if_fail (try_data
!= NULL
);
2592 if (try_data
->scope_object
) {
2593 g_assert (frame
->scope_chain
->data
== try_data
->scope_object
);
2594 frame
->scope_chain
=
2595 g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2596 try_data
->scope_object
= NULL
;
2599 if (try_data
->finally_start
&& swfdec_as_context_catch (cx
, &val
))
2601 // we got an exception while in catch block:
2602 // create new block for finally to pass on the exception
2603 // jump to that block
2605 exception_value
= g_malloc (sizeof (SwfdecAsValue
));
2606 *exception_value
= val
;
2608 // FIXME: the exception value is not marked while finally block runs
2609 swfdec_as_frame_push_block (frame
, try_data
->finally_start
,
2610 try_data
->finally_start
+ try_data
->finally_size
,
2611 swfdec_action_try_end_finally
, exception_value
);
2612 frame
->pc
= try_data
->finally_start
;
2615 swfdec_action_try_data_free (try_data
);
2619 swfdec_action_try_end_try (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2621 TryData
*try_data
= data
;
2624 g_return_if_fail (try_data
!= NULL
);
2626 // if we don't have a catch block, we handle try block exactly like it was
2628 if (!try_data
->catch_start
) {
2629 swfdec_action_try_end_catch (cx
, frame
, try_data
);
2633 if (swfdec_as_context_catch (cx
, &val
))
2635 // we got an exception while in try block:
2636 // set the exception variable
2637 // add new block for catch and jump to it
2638 try_data
->scope_object
= swfdec_as_object_new_empty (cx
);
2639 frame
->scope_chain
= g_slist_prepend (frame
->scope_chain
,
2640 try_data
->scope_object
);
2642 swfdec_as_frame_push_block (frame
, try_data
->catch_start
,
2643 try_data
->catch_start
+ try_data
->catch_size
,
2644 swfdec_action_try_end_catch
, try_data
);
2645 frame
->pc
= try_data
->catch_start
;
2647 if (try_data
->use_register
)
2649 if (try_data
->register_number
< frame
->n_registers
) {
2650 frame
->registers
[try_data
->register_number
] = val
;
2652 SWFDEC_ERROR ("cannot set Error to register %u: not enough registers",
2653 try_data
->register_number
);
2658 swfdec_as_object_set_variable (try_data
->scope_object
,
2659 swfdec_as_context_get_string (cx
, try_data
->variable_name
), &val
);
2664 swfdec_action_try_data_free (try_data
);
2669 swfdec_action_try (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2674 gboolean use_finally
, use_catch
;
2677 SWFDEC_ERROR ("With action requires a length of at least 8, but got %u",
2682 try_data
= g_malloc0 (sizeof (TryData
));
2684 swfdec_bits_init_data (&bits
, data
, len
);
2686 swfdec_bits_getbits (&bits
, 5); // reserved
2687 try_data
->use_register
= swfdec_bits_getbit (&bits
);
2688 use_finally
= swfdec_bits_getbit (&bits
);
2689 use_catch
= swfdec_bits_getbit (&bits
);
2691 try_size
= swfdec_bits_get_u16 (&bits
);
2692 try_data
->catch_size
= swfdec_bits_get_u16 (&bits
);
2693 try_data
->finally_size
= swfdec_bits_get_u16 (&bits
);
2695 try_data
->catch_start
= data
+ len
+ try_size
;
2697 try_data
->finally_start
= data
+ len
+ try_size
+
2698 (use_catch
? try_data
->catch_size
: 0);
2701 if (try_data
->use_register
) {
2702 try_data
->register_number
= swfdec_bits_get_u8 (&bits
);
2704 try_data
->variable_name
=
2705 swfdec_bits_get_string (&bits
, cx
->version
);
2708 if (swfdec_bits_left (&bits
)) {
2709 SWFDEC_WARNING ("leftover bytes in Try action");
2712 if (try_data
->catch_start
|| try_data
->finally_start
) {
2713 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ try_size
,
2714 swfdec_action_try_end_try
, try_data
);
2716 SWFDEC_WARNING ("Try with neither catch nor finally block");
2717 swfdec_action_try_data_free (try_data
);
2722 swfdec_action_pop_with (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer with_object
)
2724 g_assert (frame
->scope_chain
->data
== with_object
);
2725 frame
->scope_chain
= g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2729 swfdec_action_with (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2731 SwfdecAsObject
*object
;
2735 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2736 swfdec_as_stack_pop (cx
);
2739 offset
= data
[0] | (data
[1] << 8);
2740 object
= swfdec_as_value_to_object (cx
, *swfdec_as_stack_peek (cx
, 1));
2741 if (object
== NULL
) {
2742 SWFDEC_INFO ("With called without an object, skipping");
2743 cx
->frame
->pc
= (guint8
*) data
+ len
+ offset
;
2745 cx
->frame
->scope_chain
= g_slist_prepend (cx
->frame
->scope_chain
, object
);
2746 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ offset
,
2747 swfdec_action_pop_with
, object
);
2749 swfdec_as_stack_pop (cx
);
2753 swfdec_action_remove_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2755 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
2756 if (target
== NULL
) {
2757 SWFDEC_FIXME ("target is not a movie in RemoveSprite");
2758 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2759 SWFDEC_INFO ("tried using RemoveSprite in a non-SwfdecPlayer context");
2761 SwfdecMovie
*movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2762 swfdec_as_stack_peek (cx
, 1));
2763 if (movie
&& swfdec_depth_classify (movie
->depth
) == SWFDEC_DEPTH_CLASS_DYNAMIC
) {
2764 SWFDEC_LOG ("removing clip %s", movie
->name
);
2765 swfdec_movie_remove (movie
);
2767 SWFDEC_INFO ("cannot remove movie");
2770 swfdec_as_stack_pop (cx
);
2774 swfdec_action_clone_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2776 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
2777 SwfdecMovie
*movie
, *new_movie
;
2778 const char *new_name
;
2781 depth
= swfdec_as_value_to_integer (cx
, *swfdec_as_stack_peek (cx
, 1)) - 16384;
2782 new_name
= swfdec_as_value_to_string (cx
, *swfdec_as_stack_peek (cx
, 2));
2783 if (target
== NULL
) {
2784 SWFDEC_FIXME ("target is not a movie in CloneSprite");
2785 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2786 SWFDEC_INFO ("tried using CloneSprite in a non-SwfdecPlayer context");
2788 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2789 swfdec_as_stack_peek (cx
, 3));
2790 if (movie
== NULL
) {
2791 SWFDEC_ERROR ("Object is not an SwfdecMovie object");
2792 swfdec_as_stack_pop_n (cx
, 3);
2795 new_movie
= swfdec_movie_duplicate (movie
, new_name
, depth
);
2797 SWFDEC_LOG ("duplicated %s as %s to depth %u", movie
->name
, new_movie
->name
, new_movie
->depth
);
2800 swfdec_as_stack_pop_n (cx
, 3);
2803 /*** BIG FUNCTION TABLE ***/
2805 const SwfdecActionSpec swfdec_as_actions
[256] = {
2807 [SWFDEC_AS_ACTION_END
] = { "End", 0, 0, swfdec_action_end
, 1 },
2808 [SWFDEC_AS_ACTION_NEXT_FRAME
] = { "NextFrame", 0, 0, swfdec_action_next_frame
, 1 },
2809 [SWFDEC_AS_ACTION_PREVIOUS_FRAME
] = { "PreviousFrame", 0, 0, swfdec_action_previous_frame
, 1 },
2810 [SWFDEC_AS_ACTION_PLAY
] = { "Play", 0, 0, swfdec_action_play
, 1 },
2811 [SWFDEC_AS_ACTION_STOP
] = { "Stop", 0, 0, swfdec_action_stop
, 1 },
2812 [SWFDEC_AS_ACTION_TOGGLE_QUALITY
] = { "ToggleQuality", -1, -1, NULL
, 1 },
2814 [SWFDEC_AS_ACTION_STOP_SOUNDS
] = { "StopSounds", 0, 0, swfdec_action_stop_sounds
, 2 },
2816 [SWFDEC_AS_ACTION_ADD
] = { "Add", 2, 1, swfdec_action_binary
, 4 },
2817 [SWFDEC_AS_ACTION_SUBTRACT
] = { "Subtract", 2, 1, swfdec_action_binary
, 4 },
2818 [SWFDEC_AS_ACTION_MULTIPLY
] = { "Multiply", 2, 1, swfdec_action_binary
, 4 },
2819 [SWFDEC_AS_ACTION_DIVIDE
] = { "Divide", 2, 1, swfdec_action_binary
, 4 },
2820 [SWFDEC_AS_ACTION_EQUALS
] = { "Equals", 2, 1, swfdec_action_old_compare
, 4 },
2821 [SWFDEC_AS_ACTION_LESS
] = { "Less", 2, 1, swfdec_action_old_compare
, 4 },
2822 [SWFDEC_AS_ACTION_AND
] = { "And", 2, 1, swfdec_action_logical
, 4 },
2823 [SWFDEC_AS_ACTION_OR
] = { "Or", 2, 1, swfdec_action_logical
, 4 },
2824 [SWFDEC_AS_ACTION_NOT
] = { "Not", 1, 1, swfdec_action_not
, 4 },
2825 [SWFDEC_AS_ACTION_STRING_EQUALS
] = { "StringEquals", 2, 1, swfdec_action_string_compare
, 4 },
2826 [SWFDEC_AS_ACTION_STRING_LENGTH
] = { "StringLength", 1, 1, swfdec_action_string_length
, 4 },
2827 [SWFDEC_AS_ACTION_STRING_EXTRACT
] = { "StringExtract", 3, 1, swfdec_action_string_extract
, 4 },
2828 [SWFDEC_AS_ACTION_POP
] = { "Pop", 1, 0, swfdec_action_pop
, 4 },
2829 [SWFDEC_AS_ACTION_TO_INTEGER
] = { "ToInteger", 1, 1, swfdec_action_to_integer
, 4 },
2830 [SWFDEC_AS_ACTION_GET_VARIABLE
] = { "GetVariable", 1, 1, swfdec_action_get_variable
, 4 },
2831 [SWFDEC_AS_ACTION_SET_VARIABLE
] = { "SetVariable", 2, 0, swfdec_action_set_variable
, 4 },
2833 [SWFDEC_AS_ACTION_SET_TARGET2
] = { "SetTarget2", 1, 0, swfdec_action_set_target2
, 3 },
2835 [SWFDEC_AS_ACTION_STRING_ADD
] = { "StringAdd", 2, 1, swfdec_action_string_add
, 4 },
2836 [SWFDEC_AS_ACTION_GET_PROPERTY
] = { "GetProperty", 2, 1, swfdec_action_get_property
, 4 },
2837 [SWFDEC_AS_ACTION_SET_PROPERTY
] = { "SetProperty", 3, 0, swfdec_action_set_property
, 4 },
2838 [SWFDEC_AS_ACTION_CLONE_SPRITE
] = { "CloneSprite", 3, 0, swfdec_action_clone_sprite
, 4 },
2839 [SWFDEC_AS_ACTION_REMOVE_SPRITE
] = { "RemoveSprite", 1, 0, swfdec_action_remove_sprite
, 4 },
2840 [SWFDEC_AS_ACTION_TRACE
] = { "Trace", 1, 0, swfdec_action_trace
, 4 },
2841 [SWFDEC_AS_ACTION_START_DRAG
] = { "StartDrag", -1, 0, swfdec_action_start_drag
, 4 },
2842 [SWFDEC_AS_ACTION_END_DRAG
] = { "EndDrag", 0, 0, swfdec_action_end_drag
, 4 },
2843 [SWFDEC_AS_ACTION_STRING_LESS
] = { "StringLess", 2, 1, swfdec_action_string_compare
, 4 },
2845 [SWFDEC_AS_ACTION_THROW
] = { "Throw", 1, 0, swfdec_action_throw
, 7 },
2846 [SWFDEC_AS_ACTION_CAST
] = { "Cast", 2, 1, swfdec_action_cast
, 7 },
2847 [SWFDEC_AS_ACTION_IMPLEMENTS
] = { "Implements", -1, 0, swfdec_action_implements
, 7 },
2849 [SWFDEC_AS_ACTION_RANDOM
] = { "RandomNumber", 1, 1, swfdec_action_random_number
, 4 },
2850 [SWFDEC_AS_ACTION_MB_STRING_LENGTH
] = { "MBStringLength", 1, 1, swfdec_action_string_length
, 4 },
2851 [SWFDEC_AS_ACTION_CHAR_TO_ASCII
] = { "CharToAscii", 1, 1, swfdec_action_char_to_ascii
, 4 },
2852 [SWFDEC_AS_ACTION_ASCII_TO_CHAR
] = { "AsciiToChar", 1, 1, swfdec_action_ascii_to_char
, 4 },
2853 [SWFDEC_AS_ACTION_GET_TIME
] = { "GetTime", 0, 1, swfdec_action_get_time
, 4 },
2854 [SWFDEC_AS_ACTION_MB_STRING_EXTRACT
] = { "MBStringExtract", 3, 1, swfdec_action_string_extract
, 4 },
2855 [SWFDEC_AS_ACTION_MB_CHAR_TO_ASCII
] = { "MBCharToAscii", 1, 1, swfdec_action_char_to_ascii
, 4 },
2856 [SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
] = { "MBAsciiToChar", 1, 1, swfdec_action_ascii_to_char
, 4 },
2858 [SWFDEC_AS_ACTION_DELETE
] = { "Delete", 2, 1, swfdec_action_delete
, 5 },
2859 [SWFDEC_AS_ACTION_DELETE2
] = { "Delete2", 1, 1, swfdec_action_delete2
, 5 },
2860 [SWFDEC_AS_ACTION_DEFINE_LOCAL
] = { "DefineLocal", 2, 0, swfdec_action_define_local
, 5 },
2861 [SWFDEC_AS_ACTION_CALL_FUNCTION
] = { "CallFunction", -1, 1, swfdec_action_call_function
, 5 },
2862 [SWFDEC_AS_ACTION_RETURN
] = { "Return", 1, 0, swfdec_action_return
, 5 },
2863 [SWFDEC_AS_ACTION_MODULO
] = { "Modulo", 2, 1, swfdec_action_modulo
, 5 },
2864 [SWFDEC_AS_ACTION_NEW_OBJECT
] = { "NewObject", -1, 1, swfdec_action_new_object
, 5 },
2865 [SWFDEC_AS_ACTION_DEFINE_LOCAL2
] = { "DefineLocal2", 1, 0, swfdec_action_define_local2
, 5 },
2866 [SWFDEC_AS_ACTION_INIT_ARRAY
] = { "InitArray", -1, 1, swfdec_action_init_array
, 5 },
2867 [SWFDEC_AS_ACTION_INIT_OBJECT
] = { "InitObject", -1, 1, swfdec_action_init_object
, 5 },
2868 [SWFDEC_AS_ACTION_TYPE_OF
] = { "TypeOf", 1, 1, swfdec_action_type_of
, 5 },
2869 [SWFDEC_AS_ACTION_TARGET_PATH
] = { "TargetPath", 1, 1, swfdec_action_target_path
, 5 },
2870 [SWFDEC_AS_ACTION_ENUMERATE
] = { "Enumerate", 1, -1, swfdec_action_enumerate
, 5 },
2871 [SWFDEC_AS_ACTION_ADD2
] = { "Add2", 2, 1, swfdec_action_add2
, 5 },
2872 [SWFDEC_AS_ACTION_LESS2
] = { "Less2", 2, 1, swfdec_action_new_comparison
, 5 },
2873 [SWFDEC_AS_ACTION_EQUALS2
] = { "Equals2", 2, 1, swfdec_action_equals2
, 5 },
2874 [SWFDEC_AS_ACTION_TO_NUMBER
] = { "ToNumber", 1, 1, swfdec_action_to_number
, 5 },
2875 [SWFDEC_AS_ACTION_TO_STRING
] = { "ToString", 1, 1, swfdec_action_to_string
, 5 },
2876 [SWFDEC_AS_ACTION_PUSH_DUPLICATE
] = { "PushDuplicate", 1, 2, swfdec_action_push_duplicate
, 5 },
2877 [SWFDEC_AS_ACTION_SWAP
] = { "Swap", 2, 2, swfdec_action_swap
, 5 },
2879 [SWFDEC_AS_ACTION_GET_MEMBER
] = { "GetMember", 2, 1, swfdec_action_get_member
, 4 },
2880 [SWFDEC_AS_ACTION_SET_MEMBER
] = { "SetMember", 3, 0, swfdec_action_set_member
, 4 },
2882 [SWFDEC_AS_ACTION_INCREMENT
] = { "Increment", 1, 1, swfdec_action_increment
, 5 },
2883 [SWFDEC_AS_ACTION_DECREMENT
] = { "Decrement", 1, 1, swfdec_action_decrement
, 5 },
2884 [SWFDEC_AS_ACTION_CALL_METHOD
] = { "CallMethod", -1, 1, swfdec_action_call_method
, 5 },
2885 [SWFDEC_AS_ACTION_NEW_METHOD
] = { "NewMethod", -1, 1, swfdec_action_new_method
, 5 },
2887 [SWFDEC_AS_ACTION_INSTANCE_OF
] = { "InstanceOf", 2, 1, swfdec_action_instance_of
, 6 },
2888 [SWFDEC_AS_ACTION_ENUMERATE2
] = { "Enumerate2", 1, -1, swfdec_action_enumerate2
, 6 },
2889 [SWFDEC_AS_ACTION_BREAKPOINT
] = { "Breakpoint", -1, -1, NULL
, 6 },
2891 [SWFDEC_AS_ACTION_BIT_AND
] = { "BitAnd", 2, 1, swfdec_action_bitwise
, 5 },
2892 [SWFDEC_AS_ACTION_BIT_OR
] = { "BitOr", 2, 1, swfdec_action_bitwise
, 5 },
2893 [SWFDEC_AS_ACTION_BIT_XOR
] = { "BitXor", 2, 1, swfdec_action_bitwise
, 5 },
2894 [SWFDEC_AS_ACTION_BIT_LSHIFT
] = { "BitLShift", 2, 1, swfdec_action_shift
, 5 },
2895 [SWFDEC_AS_ACTION_BIT_RSHIFT
] = { "BitRShift", 2, 1, swfdec_action_shift
, 5 },
2896 [SWFDEC_AS_ACTION_BIT_URSHIFT
] = { "BitURShift", 2, 1, swfdec_action_shift
, 5 },
2898 [SWFDEC_AS_ACTION_STRICT_EQUALS
] = { "StrictEquals", 2, 1, swfdec_action_strict_equals
, 6 },
2899 [SWFDEC_AS_ACTION_GREATER
] = { "Greater", 2, 1, swfdec_action_new_comparison
, 6 },
2900 [SWFDEC_AS_ACTION_STRING_GREATER
] = { "StringGreater", 2, 1, swfdec_action_string_compare
, 6 },
2902 [SWFDEC_AS_ACTION_EXTENDS
] = { "Extends", 2, 0, swfdec_action_extends
, 7 },
2904 [SWFDEC_AS_ACTION_GOTO_FRAME
] = { "GotoFrame", 0, 0, swfdec_action_goto_frame
, 1 },
2905 [SWFDEC_AS_ACTION_GET_URL
] = { "GetURL", 0, 0, swfdec_action_get_url
, 1 },
2907 [SWFDEC_AS_ACTION_STORE_REGISTER
] = { "StoreRegister", 1, 1, swfdec_action_store_register
, 5 },
2908 [SWFDEC_AS_ACTION_CONSTANT_POOL
] = { "ConstantPool", 0, 0, swfdec_action_constant_pool
, 5 },
2909 [SWFDEC_AS_ACTION_STRICT_MODE
] = { "StrictMode", -1, -1, NULL
, 5 },
2911 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME
] = { "WaitForFrame", 0, 0, swfdec_action_wait_for_frame
, 1 },
2912 [SWFDEC_AS_ACTION_SET_TARGET
] = { "SetTarget", 0, 0, swfdec_action_set_target
, 1 },
2914 [SWFDEC_AS_ACTION_GOTO_LABEL
] = { "GotoLabel", 0, 0, swfdec_action_goto_label
, 3 },
2916 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME2
] = { "WaitForFrame2", 1, 0, swfdec_action_wait_for_frame2
, 4 },
2918 [SWFDEC_AS_ACTION_DEFINE_FUNCTION2
] = { "DefineFunction2", 0, -1, swfdec_action_define_function
, 7 },
2919 [SWFDEC_AS_ACTION_TRY
] = { "Try", 0, 0, swfdec_action_try
, 7 },
2921 [SWFDEC_AS_ACTION_WITH
] = { "With", 1, 0, swfdec_action_with
, 5 },
2923 [SWFDEC_AS_ACTION_PUSH
] = { "Push", 0, -1, swfdec_action_push
, 4 },
2924 [SWFDEC_AS_ACTION_JUMP
] = { "Jump", 0, 0, swfdec_action_jump
, 4 },
2925 [SWFDEC_AS_ACTION_GET_URL2
] = { "GetURL2", 2, 0, swfdec_action_get_url2
, 4 },
2927 [SWFDEC_AS_ACTION_DEFINE_FUNCTION
] = { "DefineFunction", 0, -1, swfdec_action_define_function
, 5 },
2929 [SWFDEC_AS_ACTION_IF
] = { "If", 1, 0, swfdec_action_if
, 4 },
2930 [SWFDEC_AS_ACTION_CALL
] = { "Call", -1, -1, NULL
, 4 },
2931 [SWFDEC_AS_ACTION_GOTO_FRAME2
] = { "GotoFrame2", 1, 0, swfdec_action_goto_frame2
, 4 }