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_value_set_number (cx
, swfdec_as_stack_push (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_value_set_number (cx
, swfdec_as_stack_push (cx
),
371 swfdec_bits_get_double (&bits
));
373 case 7: /* 32bit int */
374 swfdec_as_value_set_integer (cx
, swfdec_as_stack_push (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_movie_property_get (movie
, id
, swfdec_as_stack_peek (cx
, 2));
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_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), 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 (<mp
))
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_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), 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 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 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_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), 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 swfdec_as_value_set_number (cx
, val
, 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 swfdec_as_value_set_number (cx
, val
, 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 swfdec_as_value_set_number (cx
, val
, 0);
1313 swfdec_as_value_set_number (cx
, val
, 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_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), 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 swfdec_as_value_set_integer (cx
, v
, 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_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), 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);
1425 swfdec_as_value_to_primitive (&rtmp
);
1426 swfdec_as_value_to_primitive (<mp
);
1427 ltype
= SWFDEC_AS_VALUE_GET_TYPE (<mp
);
1428 rtype
= SWFDEC_AS_VALUE_GET_TYPE (&rtmp
);
1430 if (SWFDEC_AS_VALUE_IS_COMPOSITE (<mp
) && SWFDEC_AS_VALUE_IS_COMPOSITE (&rtmp
)) {
1431 /* get movies compared */
1432 if (ltype
== SWFDEC_AS_TYPE_MOVIE
) {
1433 if (rtype
== SWFDEC_AS_TYPE_MOVIE
) {
1436 swfdec_as_value_to_primitive (rval
);
1438 cond
= SWFDEC_AS_VALUE_IS_MOVIE (rval
) &&
1439 SWFDEC_AS_VALUE_GET_MOVIE (<mp
) == SWFDEC_AS_VALUE_GET_MOVIE (rval
);
1442 if (rtype
== SWFDEC_AS_TYPE_MOVIE
) {
1443 swfdec_as_value_to_primitive (lval
);
1444 cond
= SWFDEC_AS_VALUE_IS_MOVIE (lval
) &&
1445 SWFDEC_AS_VALUE_GET_MOVIE (&rtmp
) == SWFDEC_AS_VALUE_GET_MOVIE (lval
);
1449 cond
= SWFDEC_AS_VALUE_GET_OBJECT (lval
) == SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1453 /* compare strings */
1454 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1455 cond
= SWFDEC_AS_VALUE_GET_STRING (<mp
) == SWFDEC_AS_VALUE_GET_STRING (&rtmp
);
1459 /* convert to numbers */
1460 if (SWFDEC_AS_VALUE_IS_OBJECT (<mp
)) {
1461 l
= swfdec_as_value_to_number (cx
, lval
);
1463 l
= swfdec_as_value_to_number (cx
, <mp
);
1465 if (SWFDEC_AS_VALUE_IS_OBJECT (&rtmp
)) {
1466 r
= swfdec_as_value_to_number (cx
, rval
);
1468 r
= swfdec_as_value_to_number (cx
, &rtmp
);
1471 /* get rid of undefined and null */
1472 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1473 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1480 /* else compare as numbers */
1481 if (isnan (l
) && isnan (r
)) {
1482 cond
= (ltype
== SWFDEC_AS_TYPE_NUMBER
&& ltmp
== rtmp
);
1488 swfdec_as_stack_pop (cx
);
1489 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1493 swfdec_action_equals2_6 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1495 SwfdecAsValue
*rval
, *lval
;
1496 SwfdecAsValueType ltype
, rtype
;
1500 rval
= swfdec_as_stack_peek (cx
, 1);
1501 lval
= swfdec_as_stack_peek (cx
, 2);
1502 /* check objects before anything else */
1503 if (SWFDEC_AS_VALUE_IS_OBJECT (lval
) && SWFDEC_AS_VALUE_IS_OBJECT (rval
)) {
1504 cond
= SWFDEC_AS_VALUE_GET_OBJECT (lval
) == SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1507 swfdec_as_value_to_primitive (lval
);
1508 swfdec_as_value_to_primitive (rval
);
1510 /* check if we have equal movieclips */
1511 if (SWFDEC_AS_VALUE_IS_MOVIE (lval
)) {
1512 cond
= SWFDEC_AS_VALUE_IS_MOVIE (rval
) &&
1513 SWFDEC_AS_VALUE_GET_MOVIE (lval
) == SWFDEC_AS_VALUE_GET_MOVIE (rval
);
1517 /* now all composites compare false */
1518 if (SWFDEC_AS_VALUE_IS_COMPOSITE (lval
) ||
1519 SWFDEC_AS_VALUE_IS_COMPOSITE (rval
)) {
1524 ltype
= SWFDEC_AS_VALUE_GET_TYPE (lval
);
1525 rtype
= SWFDEC_AS_VALUE_GET_TYPE (rval
);
1527 /* get rid of undefined and null */
1528 cond
= rtype
== SWFDEC_AS_TYPE_UNDEFINED
|| rtype
== SWFDEC_AS_TYPE_NULL
;
1529 if (ltype
== SWFDEC_AS_TYPE_UNDEFINED
|| ltype
== SWFDEC_AS_TYPE_NULL
) {
1536 /* compare strings */
1537 if (ltype
== SWFDEC_AS_TYPE_STRING
&& rtype
== SWFDEC_AS_TYPE_STRING
) {
1538 cond
= SWFDEC_AS_VALUE_GET_STRING (lval
) == SWFDEC_AS_VALUE_GET_STRING (rval
);
1542 /* else compare as numbers */
1543 l
= swfdec_as_value_to_number (cx
, lval
);
1544 r
= swfdec_as_value_to_number (cx
, rval
);
1546 if (isnan (l
) && isnan (r
)) {
1547 cond
= (ltype
== SWFDEC_AS_TYPE_NUMBER
&& *lval
== *rval
);
1553 swfdec_as_stack_pop (cx
);
1554 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1558 swfdec_action_equals2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1560 if (cx
->version
<= 5) {
1561 swfdec_action_equals2_5 (cx
, action
, data
, len
);
1563 swfdec_action_equals2_6 (cx
, action
, data
, len
);
1568 swfdec_action_strict_equals (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1570 SwfdecAsValue
*rval
, *lval
;
1573 rval
= swfdec_as_stack_peek (cx
, 1);
1574 lval
= swfdec_as_stack_peek (cx
, 2);
1576 if (SWFDEC_AS_VALUE_GET_TYPE (rval
) != SWFDEC_AS_VALUE_GET_TYPE (lval
)) {
1579 switch (SWFDEC_AS_VALUE_GET_TYPE (rval
)) {
1580 case SWFDEC_AS_TYPE_UNDEFINED
:
1581 case SWFDEC_AS_TYPE_NULL
:
1584 case SWFDEC_AS_TYPE_BOOLEAN
:
1585 cond
= SWFDEC_AS_VALUE_GET_BOOLEAN (rval
) == SWFDEC_AS_VALUE_GET_BOOLEAN (lval
);
1587 case SWFDEC_AS_TYPE_NUMBER
:
1590 r
= SWFDEC_AS_VALUE_GET_NUMBER (rval
);
1591 l
= SWFDEC_AS_VALUE_GET_NUMBER (lval
);
1592 cond
= (l
== r
) || (isnan (l
) && isnan (r
));
1595 case SWFDEC_AS_TYPE_STRING
:
1596 cond
= SWFDEC_AS_VALUE_GET_STRING (rval
) == SWFDEC_AS_VALUE_GET_STRING (lval
);
1598 case SWFDEC_AS_TYPE_OBJECT
:
1599 cond
= SWFDEC_AS_VALUE_GET_OBJECT (lval
) == SWFDEC_AS_VALUE_GET_OBJECT (rval
);
1601 case SWFDEC_AS_TYPE_MOVIE
:
1602 cond
= SWFDEC_AS_VALUE_GET_MOVIE (lval
) == SWFDEC_AS_VALUE_GET_MOVIE (rval
);
1604 case SWFDEC_AS_TYPE_INT
:
1606 g_assert_not_reached ();
1611 swfdec_as_stack_pop (cx
);
1612 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 1), cond
);
1616 swfdec_action_do_set_target (SwfdecAsContext
*cx
, const char *target
, const char *end
)
1618 swfdec_as_frame_set_target (cx
->frame
, NULL
);
1620 if (target
!= end
) {
1621 SwfdecAsObject
*o
= swfdec_action_lookup_object (cx
, NULL
, target
, end
);
1623 SWFDEC_WARNING ("target \"%s\" is not an object", target
);
1624 } else if (!o
->movie
) {
1625 SWFDEC_FIXME ("target \"%s\" is not a movie, something weird is supposed to happen now", target
);
1627 swfdec_as_frame_set_target (cx
->frame
, SWFDEC_MOVIE (o
->relay
));
1633 swfdec_action_set_target (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1637 end
= memchr (data
, 0, len
);
1639 SWFDEC_ERROR ("SetTarget action does not specify a string");
1642 swfdec_action_do_set_target (cx
, (const char *) data
, end
);
1646 swfdec_action_set_target2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1650 s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1651 swfdec_action_do_set_target (cx
, s
, s
+ strlen (s
));
1652 swfdec_as_stack_pop (cx
);
1656 swfdec_action_start_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1658 SwfdecRect rect
, *rectp
= NULL
;
1661 guint stack_size
= 3;
1663 swfdec_as_stack_ensure_size (cx
, 3);
1664 center
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
1665 if (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 3))) {
1666 swfdec_as_stack_ensure_size (cx
, 7);
1667 rect
.x0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 7));
1668 rect
.y0
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 6));
1669 rect
.x1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 5));
1670 rect
.y1
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 4));
1671 swfdec_rect_scale (&rect
, &rect
, SWFDEC_TWIPS_SCALE_FACTOR
);
1675 if (!SWFDEC_IS_PLAYER (cx
)) {
1676 SWFDEC_ERROR ("called startDrag on a non-SwfdecPlayer");
1678 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
), swfdec_as_stack_peek (cx
, 1));
1679 if (SWFDEC_IS_ACTOR (movie
)) {
1680 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), SWFDEC_ACTOR (movie
), center
, rectp
);
1682 SWFDEC_ERROR ("startDrag on something not an Actor");
1685 swfdec_as_stack_pop_n (cx
, stack_size
);
1689 swfdec_action_end_drag (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1691 if (SWFDEC_IS_PLAYER (cx
)) {
1692 swfdec_player_set_drag_movie (SWFDEC_PLAYER (cx
), NULL
, FALSE
, NULL
);
1694 SWFDEC_WARNING ("can't end a drag on non-players");
1699 swfdec_action_stop_sounds (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1701 if (SWFDEC_IS_PLAYER (cx
)) {
1702 swfdec_player_stop_all_sounds (SWFDEC_PLAYER (cx
));
1707 swfdec_action_new_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1709 SwfdecAsValue
*constructor
;
1710 SwfdecAsFunction
*fun
;
1713 swfdec_as_stack_ensure_size (cx
, 2);
1714 swfdec_action_get_variable (cx
, action
, data
, len
);
1715 constructor
= swfdec_as_stack_peek (cx
, 1);
1716 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1717 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 2, n_args
);
1718 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1719 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
)->relay
)) {
1720 SWFDEC_WARNING ("not a constructor");
1724 swfdec_as_stack_pop_n (cx
, 2);
1725 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1729 swfdec_as_stack_pop_n (cx
, n_args
+ 1);
1730 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1734 swfdec_action_new_method (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1736 SwfdecAsValue
*constructor
;
1737 SwfdecAsFunction
*fun
;
1741 swfdec_as_stack_ensure_size (cx
, 3);
1742 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
1744 constructor
= swfdec_as_stack_peek (cx
, 2);
1745 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 3));
1746 n_args
= MIN (swfdec_as_stack_get_size (cx
) - 3, n_args
);
1747 if (name
== SWFDEC_AS_STR_EMPTY
||
1748 SWFDEC_AS_VALUE_IS_UNDEFINED (swfdec_as_stack_peek (cx
, 1))) {
1750 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (constructor
)) {
1751 SWFDEC_WARNING ("NewMethod called without an object to get variable %s from", name
);
1754 swfdec_as_object_get_variable (SWFDEC_AS_VALUE_GET_COMPOSITE (constructor
),
1757 if (!SWFDEC_AS_VALUE_IS_OBJECT (constructor
) ||
1758 !SWFDEC_IS_AS_FUNCTION (fun
= (SwfdecAsFunction
*) SWFDEC_AS_VALUE_GET_OBJECT (constructor
)->relay
)) {
1759 SWFDEC_WARNING ("%s is not a constructor", name
);
1763 swfdec_as_stack_pop_n (cx
, 3);
1764 swfdec_as_object_create (fun
, n_args
, NULL
, NULL
);
1768 swfdec_as_stack_pop_n (cx
, n_args
+ 2);
1769 SWFDEC_AS_VALUE_SET_UNDEFINED (swfdec_as_stack_peek (cx
, 1));
1773 swfdec_action_init_object (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1775 SwfdecAsObject
*object
;
1776 guint i
, n_args
, size
;
1778 n_args
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1779 swfdec_as_stack_pop (cx
);
1780 if (n_args
* 2 > swfdec_as_stack_get_size (cx
)) {
1781 size
= swfdec_as_stack_get_size (cx
);
1782 SWFDEC_FIXME ("InitObject action with too small stack, help!");
1789 object
= swfdec_as_object_new (cx
, NULL
);
1790 swfdec_as_object_set_constructor_by_name (object
, SWFDEC_AS_STR_Object
, NULL
);
1791 for (i
= 0; i
< n_args
; i
++) {
1792 const char *s
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
1793 swfdec_as_object_set_variable (object
, s
, swfdec_as_stack_peek (cx
, 1));
1794 swfdec_as_stack_pop_n (cx
, 2);
1796 swfdec_as_stack_pop_n (cx
, size
);
1797 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), object
);
1801 swfdec_action_init_array (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1804 SwfdecAsObject
*array
;
1806 swfdec_as_stack_ensure_size (cx
, 1);
1807 n
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1808 swfdec_as_stack_pop (cx
);
1809 array
= swfdec_as_array_new (cx
);
1810 /* NB: we can't increase the stack here, as the number can easily be MAXINT */
1811 for (i
= 0; i
< n
&& swfdec_as_stack_get_size (cx
) > 0; i
++) {
1812 swfdec_as_stack_ensure_size (cx
, 1);
1813 swfdec_as_array_push (array
, swfdec_as_stack_pop (cx
));
1817 swfdec_as_value_set_integer (cx
, &val
, n
);
1818 swfdec_as_object_set_variable (array
, SWFDEC_AS_STR_length
, &val
);
1820 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
), array
);
1824 swfdec_action_define_function (SwfdecAsContext
*cx
, guint action
,
1825 const guint8
*data
, guint len
)
1827 char *function_name
;
1828 const char *name
= NULL
;
1829 guint i
, n_args
, size
, n_registers
;
1831 SwfdecBuffer
*buffer
;
1832 SwfdecAsFunction
*fun
;
1833 SwfdecAsFrame
*frame
;
1834 SwfdecScript
*script
;
1836 SwfdecScriptArgument
*args
;
1837 gboolean v2
= (action
== 0x8e);
1840 swfdec_bits_init_data (&bits
, data
, len
);
1841 function_name
= swfdec_bits_get_string (&bits
, cx
->version
);
1842 if (function_name
== NULL
) {
1843 SWFDEC_ERROR ("could not parse function name");
1846 n_args
= swfdec_bits_get_u16 (&bits
);
1848 n_registers
= swfdec_bits_get_u8 (&bits
);
1849 if (n_registers
== 0)
1851 flags
= swfdec_bits_get_u16 (&bits
);
1856 args
= g_new0 (SwfdecScriptArgument
, n_args
);
1857 for (i
= 0; i
< n_args
&& swfdec_bits_left (&bits
); i
++) {
1859 args
[i
].preload
= swfdec_bits_get_u8 (&bits
);
1860 if (args
[i
].preload
&& args
[i
].preload
>= n_registers
) {
1861 SWFDEC_ERROR ("argument %u cannot be preloaded into register %u out of %u",
1862 i
, args
[i
].preload
, n_registers
);
1863 /* FIXME: figure out correct error handling here */
1864 args
[i
].preload
= 0;
1867 args
[i
].name
= swfdec_bits_get_string (&bits
, cx
->version
);
1868 if (args
[i
].name
== NULL
|| args
[i
].name
== '\0') {
1869 SWFDEC_ERROR ("empty argument name not allowed");
1873 /* FIXME: check duplicate arguments */
1878 size
= swfdec_bits_get_u16 (&bits
);
1879 /* check the script can be created */
1880 if (frame
->script
->buffer
->data
+ frame
->script
->buffer
->length
< frame
->pc
+ 3 + len
+ size
) {
1881 SWFDEC_ERROR ("size of function is too big");
1883 g_free (function_name
);
1886 /* create the script */
1887 buffer
= swfdec_buffer_new_subbuffer (frame
->script
->buffer
,
1888 frame
->pc
+ 3 + len
- frame
->script
->buffer
->data
, size
);
1889 swfdec_bits_init (&bits
, buffer
);
1890 if (*function_name
) {
1891 name
= function_name
;
1892 } else if (swfdec_as_stack_get_size (cx
) > 0) {
1893 /* This is kind of a hack that uses a feature of the Adobe compiler:
1894 * foo = function () {} is compiled as these actions:
1895 * Push "foo", DefineFunction, SetVariable/SetMember
1896 * With this knowledge we can inspect the topmost stack member, since
1897 * it will contain the name this function will soon be assigned to.
1899 if (SWFDEC_AS_VALUE_IS_STRING (swfdec_as_stack_peek (cx
, 1)))
1900 name
= SWFDEC_AS_VALUE_GET_STRING (swfdec_as_stack_peek (cx
, 1));
1903 name
= "unnamed_function";
1904 script
= swfdec_script_new_from_bits (&bits
, name
, cx
->version
);
1905 swfdec_buffer_unref (buffer
);
1906 if (script
== NULL
) {
1907 SWFDEC_ERROR ("failed to create script");
1909 g_free (function_name
);
1912 if (frame
->constant_pool
)
1913 script
->constant_pool
= swfdec_buffer_ref (swfdec_constant_pool_get_buffer (frame
->constant_pool
));
1914 script
->flags
= flags
;
1915 script
->n_registers
= n_registers
;
1916 script
->n_arguments
= n_args
;
1917 script
->arguments
= args
;
1918 /* see function-scope tests */
1919 if (cx
->version
> 5) {
1920 /* FIXME: or original target? */
1921 fun
= swfdec_as_script_function_new (cx
, frame
->original_target
, frame
->scope_chain
, script
);
1923 fun
= swfdec_as_script_function_new (cx
, frame
->original_target
, NULL
, script
);
1925 /* This is a hack that should only trigger for functions defined in the init scripts.
1926 * It is supposed to ensure that those functions inherit their target when being
1927 * called instead of when being defined */
1928 if (!SWFDEC_IS_MOVIE (frame
->original_target
))
1929 SWFDEC_AS_SCRIPT_FUNCTION (fun
)->target
= NULL
;
1930 /* attach the function */
1931 if (*function_name
== '\0') {
1932 swfdec_as_stack_ensure_free (cx
, 1);
1933 SWFDEC_AS_VALUE_SET_OBJECT (swfdec_as_stack_push (cx
),
1934 swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (fun
)));
1936 SwfdecAsValue funval
;
1937 SwfdecMovie
*target
= frame
->original_target
;
1939 name
= swfdec_as_context_get_string (cx
, function_name
);
1940 SWFDEC_AS_VALUE_SET_OBJECT (&funval
, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (fun
)));
1941 swfdec_as_object_set_variable (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target
)),
1946 /* update current context */
1947 frame
->pc
+= 3 + len
+ size
;
1948 g_free (function_name
);
1952 swfdec_action_bitwise (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1956 a
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1957 b
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1970 g_assert_not_reached ();
1974 swfdec_as_stack_pop (cx
);
1975 swfdec_as_value_set_integer (cx
, swfdec_as_stack_peek (cx
, 1), a
);
1979 swfdec_action_shift (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
1983 amount
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1));
1985 value
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 2));
1989 value
= value
<< amount
;
1992 value
= ((gint
) value
) >> amount
;
1995 value
= ((guint
) value
) >> amount
;
1998 g_assert_not_reached ();
2001 swfdec_as_stack_pop (cx
);
2002 swfdec_as_value_set_integer (cx
, swfdec_as_stack_peek (cx
, 1), value
);
2006 swfdec_action_to_integer (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2008 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2010 swfdec_as_value_set_integer (cx
, val
, swfdec_as_value_to_integer (cx
, val
));
2014 swfdec_action_target_path (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2019 val
= swfdec_as_stack_peek (cx
, 1);
2021 if (!SWFDEC_AS_VALUE_IS_MOVIE (val
)) {
2022 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2025 s
= swfdec_movie_get_path (SWFDEC_AS_VALUE_GET_MOVIE (val
), TRUE
);
2026 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_give_string (cx
, s
));
2030 swfdec_action_define_local (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2034 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
2035 swfdec_as_frame_set_variable (cx
, cx
->frame
, name
, swfdec_as_stack_peek (cx
, 1),
2037 swfdec_as_stack_pop_n (cx
, 2);
2041 swfdec_action_define_local2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2043 SwfdecAsValue val
= { 0, };
2046 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
2047 swfdec_as_frame_set_variable (cx
, cx
->frame
, name
, &val
, FALSE
, TRUE
);
2048 swfdec_as_stack_pop (cx
);
2052 swfdec_action_end (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2054 swfdec_as_context_return (cx
, NULL
);
2058 swfdec_action_return (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2060 swfdec_as_context_return (cx
, swfdec_as_stack_pop (cx
));
2064 swfdec_action_delete (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2068 gboolean success
= FALSE
;
2070 name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1));
2071 val
= swfdec_as_stack_peek (cx
, 2);
2072 if (SWFDEC_AS_VALUE_IS_COMPOSITE (val
)) {
2073 SwfdecAsObject
*o
= SWFDEC_AS_VALUE_GET_COMPOSITE (val
);
2075 success
= swfdec_as_object_delete_variable (o
, name
) == SWFDEC_AS_DELETE_DELETED
;
2077 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
2078 swfdec_as_stack_pop_n (cx
, 1);
2082 swfdec_action_delete2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2086 gboolean success
= FALSE
;
2088 val
= swfdec_as_stack_peek (cx
, 1);
2089 name
= swfdec_as_value_to_string (cx
, val
);
2090 success
= swfdec_as_frame_delete_variable (cx
, cx
->frame
, name
) == SWFDEC_AS_DELETE_DELETED
;
2091 SWFDEC_AS_VALUE_SET_BOOLEAN (val
, success
);
2095 swfdec_action_store_register (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2098 SWFDEC_ERROR ("StoreRegister action requires a length of 1, but got %u", len
);
2101 if (!swfdec_action_has_register (cx
, *data
)) {
2102 SWFDEC_ERROR ("Cannot store into register %u, not enough registers", (guint
) *data
);
2105 cx
->frame
->registers
[*data
] = *swfdec_as_stack_peek (cx
, 1);
2109 swfdec_action_modulo (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2113 y
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1));
2114 x
= swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2));
2115 /* yay, we're portable! */
2122 SWFDEC_FIXME ("errno set after fmod");
2125 swfdec_as_stack_pop (cx
);
2126 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1), x
);
2130 swfdec_action_swap (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2132 swfdec_as_stack_swap (cx
, 1, 2);
2136 swfdec_action_to_number (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2138 swfdec_as_value_set_number (cx
, swfdec_as_stack_peek (cx
, 1),
2139 swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)));
2143 swfdec_action_to_string (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2145 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_peek (cx
, 1),
2146 swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 1)));
2150 swfdec_action_type_of (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2155 val
= swfdec_as_stack_peek (cx
, 1);
2156 switch (SWFDEC_AS_VALUE_GET_TYPE (val
)) {
2157 case SWFDEC_AS_TYPE_NUMBER
:
2158 type
= SWFDEC_AS_STR_number
;
2160 case SWFDEC_AS_TYPE_BOOLEAN
:
2161 type
= SWFDEC_AS_STR_boolean
;
2163 case SWFDEC_AS_TYPE_STRING
:
2164 type
= SWFDEC_AS_STR_string
;
2166 case SWFDEC_AS_TYPE_UNDEFINED
:
2167 type
= SWFDEC_AS_STR_undefined
;
2169 case SWFDEC_AS_TYPE_NULL
:
2170 type
= SWFDEC_AS_STR_null
;
2172 case SWFDEC_AS_TYPE_OBJECT
:
2174 SwfdecAsObject
*obj
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2175 if (SWFDEC_IS_AS_FUNCTION (obj
->relay
)) {
2176 type
= SWFDEC_AS_STR_function
;
2178 type
= SWFDEC_AS_STR_object
;
2182 case SWFDEC_AS_TYPE_MOVIE
:
2184 SwfdecMovie
*movie
= SWFDEC_AS_VALUE_GET_MOVIE (val
);
2185 if (SWFDEC_IS_TEXT_FIELD_MOVIE (movie
) &&
2186 movie
->state
== SWFDEC_MOVIE_STATE_RUNNING
) {
2187 type
= SWFDEC_AS_STR_object
;
2189 type
= SWFDEC_AS_STR_movieclip
;
2193 case SWFDEC_AS_TYPE_INT
:
2195 g_assert_not_reached ();
2196 type
= SWFDEC_AS_STR_EMPTY
;
2199 SWFDEC_AS_VALUE_SET_STRING (val
, type
);
2203 swfdec_action_get_time (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2208 swfdec_as_context_get_time (cx
, &tv
);
2209 /* we assume here that swfdec_as_context_get_time always returns a tv > start_time */
2210 diff
= tv
.tv_sec
- cx
->start_time
.tv_sec
;
2212 diff
+= (tv
.tv_usec
- cx
->start_time
.tv_usec
) / 1000;
2214 swfdec_as_value_set_number (cx
, swfdec_as_stack_push (cx
), diff
);
2218 swfdec_action_is_instance_of (SwfdecAsObject
*object
,
2219 SwfdecAsObject
*constructor
)
2222 SwfdecAsObject
*class, *prototype
;
2225 g_return_val_if_fail (object
!= NULL
, FALSE
);
2226 g_return_val_if_fail (constructor
!= NULL
, FALSE
);
2228 // FIXME: propflag tests are wrong, and we shouldn't get __proto__.prototype
2229 swfdec_as_object_get_variable (constructor
, SWFDEC_AS_STR_prototype
, &val
);
2230 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
2232 prototype
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
2235 while ((class = swfdec_as_object_get_prototype (class)) != NULL
) {
2236 if (class == prototype
)
2238 for (iter
= class->interfaces
; iter
!= NULL
; iter
= iter
->next
) {
2239 if (iter
->data
== prototype
)
2248 swfdec_action_instance_of (SwfdecAsContext
*cx
, guint action
,
2249 const guint8
*data
, guint len
)
2252 SwfdecAsObject
*object
, *constructor
;
2254 val
= swfdec_as_stack_pop (cx
);
2255 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2256 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2261 val
= swfdec_as_stack_pop (cx
);
2262 if (SWFDEC_AS_VALUE_IS_COMPOSITE (val
)) {
2263 object
= SWFDEC_AS_VALUE_GET_COMPOSITE (val
);
2269 if (object
== NULL
|| constructor
== NULL
) {
2270 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
), FALSE
);
2274 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_push (cx
),
2275 swfdec_action_is_instance_of (object
, constructor
));
2279 swfdec_action_cast (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2283 SwfdecAsObject
*object
, *constructor
;
2285 val
= swfdec_as_stack_pop (cx
);
2286 if (SWFDEC_AS_VALUE_IS_COMPOSITE (val
)) {
2287 object
= SWFDEC_AS_VALUE_GET_COMPOSITE (val
);
2292 val
= swfdec_as_stack_pop (cx
);
2293 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2294 constructor
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2299 if (object
== NULL
|| constructor
== NULL
) {
2300 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2304 if (swfdec_action_is_instance_of (object
, constructor
)) {
2305 SWFDEC_AS_VALUE_SET_COMPOSITE (swfdec_as_stack_push (cx
), object
);
2307 SWFDEC_AS_VALUE_SET_NULL (swfdec_as_stack_push (cx
));
2312 swfdec_action_implements (SwfdecAsContext
*cx
, guint action
,
2313 const guint8
*data
, guint len
)
2315 SwfdecAsValue
*val
, *argv
;
2316 SwfdecAsObject
*object
, *proto
;
2319 swfdec_as_stack_ensure_size (cx
, 2);
2321 val
= swfdec_as_stack_pop (cx
);
2322 if (SWFDEC_AS_VALUE_IS_COMPOSITE (val
)) {
2323 object
= SWFDEC_AS_VALUE_GET_COMPOSITE (val
);
2324 swfdec_as_object_get_variable (object
, SWFDEC_AS_STR_prototype
, val
);
2325 if (SWFDEC_AS_VALUE_IS_OBJECT (val
)) {
2326 proto
= SWFDEC_AS_VALUE_GET_OBJECT (val
);
2335 val
= swfdec_as_stack_pop (cx
);
2336 argc
= swfdec_as_value_to_integer (cx
, val
);
2339 swfdec_as_stack_ensure_size (cx
, argc
);
2340 argv
= swfdec_as_stack_pop_n (cx
, argc
);
2348 for (i
= 0; i
< argc
; i
++) {
2349 swfdec_as_value_get_variable (cx
, &argv
[i
], SWFDEC_AS_STR_prototype
, val
);
2350 if (!SWFDEC_AS_VALUE_IS_OBJECT (val
))
2353 g_slist_prepend (proto
->interfaces
, SWFDEC_AS_VALUE_GET_OBJECT (val
));
2358 swfdec_action_extends (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2360 SwfdecAsValue
*superclass
, *subclass
, proto
;
2361 SwfdecAsObject
*prototype
;
2362 SwfdecAsObject
*super
;
2364 superclass
= swfdec_as_stack_peek (cx
, 1);
2365 subclass
= swfdec_as_stack_peek (cx
, 2);
2366 if (!SWFDEC_AS_VALUE_IS_OBJECT (superclass
) ||
2367 !SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (superclass
)->relay
)) {
2368 SWFDEC_ERROR ("superclass is not a function");
2371 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (subclass
)) {
2372 SWFDEC_ERROR ("subclass is not an object");
2375 super
= SWFDEC_AS_VALUE_GET_OBJECT (superclass
);
2376 prototype
= swfdec_as_object_new_empty (cx
);
2377 swfdec_as_object_get_variable (super
, SWFDEC_AS_STR_prototype
, &proto
);
2378 swfdec_as_object_set_variable_and_flags (prototype
, SWFDEC_AS_STR___proto__
, &proto
,
2379 SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_PERMANENT
);
2380 swfdec_as_object_set_variable_and_flags (prototype
, SWFDEC_AS_STR___constructor__
,
2381 superclass
, SWFDEC_AS_VARIABLE_HIDDEN
| SWFDEC_AS_VARIABLE_VERSION_6_UP
);
2382 SWFDEC_AS_VALUE_SET_OBJECT (&proto
, prototype
);
2383 swfdec_as_object_set_variable (SWFDEC_AS_VALUE_GET_COMPOSITE (subclass
),
2384 SWFDEC_AS_STR_prototype
, &proto
);
2386 swfdec_as_stack_pop_n (cx
, 2);
2390 swfdec_action_enumerate_foreach (SwfdecAsObject
*object
, const char *variable
,
2391 SwfdecAsValue
*value
, guint flags
, gpointer listp
)
2393 GSList
**list
= listp
;
2395 if (flags
& SWFDEC_AS_VARIABLE_HIDDEN
)
2398 *list
= g_slist_remove (*list
, variable
);
2399 *list
= g_slist_prepend (*list
, (gpointer
) variable
);
2404 swfdec_action_do_enumerate (SwfdecAsContext
*cx
, SwfdecAsObject
*object
)
2407 GSList
*walk
, *list
= NULL
;
2409 for (i
= 0; i
< 256 && object
; i
++) {
2410 swfdec_as_object_foreach (object
, swfdec_action_enumerate_foreach
, &list
);
2411 object
= swfdec_as_object_get_prototype (object
);
2414 swfdec_as_context_abort (cx
, "Prototype recursion limit exceeded");
2415 g_slist_free (list
);
2418 list
= g_slist_reverse (list
);
2420 for (walk
= list
; walk
; walk
= walk
->next
) {
2421 /* 8 is an arbitrary value */
2423 swfdec_as_stack_ensure_free (cx
, 8);
2427 SWFDEC_AS_VALUE_SET_STRING (swfdec_as_stack_push (cx
), walk
->data
);
2429 g_slist_free (list
);
2433 swfdec_action_enumerate2 (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2436 SwfdecAsObject
*obj
;
2438 val
= swfdec_as_stack_peek (cx
, 1);
2439 if (!SWFDEC_AS_VALUE_IS_COMPOSITE (val
) ||
2440 (obj
= SWFDEC_AS_VALUE_GET_COMPOSITE (val
)) == NULL
) {
2441 SWFDEC_WARNING ("Enumerate called without an object");
2442 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2445 SWFDEC_AS_VALUE_SET_UNDEFINED (val
);
2446 swfdec_action_do_enumerate (cx
, obj
);
2450 swfdec_action_enumerate (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2452 /* FIXME: make this proper functions */
2453 swfdec_action_get_variable (cx
, action
, data
, len
);
2454 swfdec_action_enumerate2 (cx
, action
, data
, len
);
2458 swfdec_action_logical (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2462 if (cx
->version
<= 4) {
2463 l
= (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 1)) != 0);
2464 // don't call second parameter if not necessary
2465 if ((action
== SWFDEC_AS_ACTION_AND
&& !l
) ||
2466 (action
!= SWFDEC_AS_ACTION_AND
&& l
)) {
2467 r
= (swfdec_as_value_to_number (cx
, swfdec_as_stack_peek (cx
, 2)) != 0);
2472 l
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 1));
2473 r
= swfdec_as_value_to_boolean (cx
, swfdec_as_stack_peek (cx
, 2));
2476 SWFDEC_AS_VALUE_SET_BOOLEAN (swfdec_as_stack_peek (cx
, 2),
2477 (action
== SWFDEC_AS_ACTION_AND
) ? (l
&& r
) : (l
|| r
));
2478 swfdec_as_stack_pop (cx
);
2482 swfdec_action_char_to_ascii (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2484 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2485 const char *s
= swfdec_as_value_to_string (cx
, val
);
2487 if (cx
->version
<= 5) {
2488 char *ascii
= g_convert (s
, -1, "LATIN1", "UTF-8", NULL
, NULL
, NULL
);
2490 if (ascii
== NULL
) {
2491 /* This can happen if a Flash 5 movie gets loaded into a Flash 7 movie */
2492 SWFDEC_FIXME ("Someone threw unconvertible text %s at Flash <= 5", s
);
2493 swfdec_as_value_set_integer (cx
, val
, 0); /* FIXME: what to return??? */
2495 swfdec_as_value_set_integer (cx
, val
, (guchar
) ascii
[0]);
2499 gunichar
*uni
= g_utf8_to_ucs4_fast (s
, -1, NULL
);
2502 /* This should never happen, everything is valid UTF-8 in here */
2503 g_warning ("conversion of character %s failed", s
);
2504 swfdec_as_value_set_integer (cx
, val
, 0);
2506 swfdec_as_value_set_integer (cx
, val
, uni
[0]);
2513 swfdec_action_ascii_to_char (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2515 SwfdecAsValue
*val
= swfdec_as_stack_peek (cx
, 1);
2517 if (cx
->version
<= 5) {
2522 if (action
== SWFDEC_AS_ACTION_ASCII_TO_CHAR
) {
2523 s
[0] = ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 256;
2526 g_assert (action
== SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
);
2528 i
= ((guint
) swfdec_as_value_to_integer (cx
, val
));
2539 utf8
= g_convert (s
, -1, "UTF-8", "LATIN1", NULL
, NULL
, NULL
);
2541 g_warning ("conversion of character %u failed", (guint
) s
[0]);
2542 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2544 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, utf8
));
2549 gunichar c
= ((guint
) swfdec_as_value_to_integer (cx
, val
)) % 65536;
2551 s
= g_ucs4_to_utf8 (&c
, 1, NULL
, NULL
, NULL
);
2553 g_warning ("conversion of character %u failed", (guint
) c
);
2554 SWFDEC_AS_VALUE_SET_STRING (val
, SWFDEC_AS_STR_EMPTY
);
2556 SWFDEC_AS_VALUE_SET_STRING (val
, swfdec_as_context_get_string (cx
, s
));
2563 swfdec_action_throw (SwfdecAsContext
*cx
, guint action
, const guint8
*data
,
2566 swfdec_as_context_throw (cx
, swfdec_as_stack_pop (cx
));
2570 const guint8
* catch_start
;
2571 const guint8
* finally_start
;
2575 gboolean use_register
;
2577 guint register_number
;
2578 char * variable_name
;
2581 SwfdecAsObject
* scope_object
;
2585 swfdec_action_try_data_free (gpointer data
)
2587 TryData
*try_data
= data
;
2589 g_return_if_fail (try_data
!= NULL
);
2591 if (!try_data
->use_register
)
2592 g_free (try_data
->variable_name
);
2597 swfdec_action_try_end_finally (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2599 SwfdecAsValue
*exception_value
= data
;
2602 // finally has ended and we had exception stored, throw it
2603 if (!cx
->exception
&& cx
->frame
== frame
)
2604 swfdec_as_context_throw (cx
, exception_value
);
2610 swfdec_action_try_end_catch (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2612 TryData
*try_data
= data
;
2613 SwfdecAsValue
*exception_value
, val
;
2615 g_return_if_fail (try_data
!= NULL
);
2617 if (try_data
->scope_object
) {
2618 g_assert (frame
->scope_chain
->data
== try_data
->scope_object
);
2619 frame
->scope_chain
=
2620 g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2621 try_data
->scope_object
= NULL
;
2624 if (try_data
->finally_start
&& swfdec_as_context_catch (cx
, &val
))
2626 // we got an exception while in catch block:
2627 // create new block for finally to pass on the exception
2628 // jump to that block
2630 exception_value
= g_malloc (sizeof (SwfdecAsValue
));
2631 *exception_value
= val
;
2633 // FIXME: the exception value is not marked while finally block runs
2634 swfdec_as_frame_push_block (frame
, try_data
->finally_start
,
2635 try_data
->finally_start
+ try_data
->finally_size
,
2636 swfdec_action_try_end_finally
, exception_value
);
2637 frame
->pc
= try_data
->finally_start
;
2640 swfdec_action_try_data_free (try_data
);
2644 swfdec_action_try_end_try (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer data
)
2646 TryData
*try_data
= data
;
2649 g_return_if_fail (try_data
!= NULL
);
2651 // if we don't have a catch block, we handle try block exactly like it was
2653 if (!try_data
->catch_start
) {
2654 swfdec_action_try_end_catch (cx
, frame
, try_data
);
2658 if (swfdec_as_context_catch (cx
, &val
))
2660 // we got an exception while in try block:
2661 // set the exception variable
2662 // add new block for catch and jump to it
2663 try_data
->scope_object
= swfdec_as_object_new_empty (cx
);
2664 frame
->scope_chain
= g_slist_prepend (frame
->scope_chain
,
2665 try_data
->scope_object
);
2667 swfdec_as_frame_push_block (frame
, try_data
->catch_start
,
2668 try_data
->catch_start
+ try_data
->catch_size
,
2669 swfdec_action_try_end_catch
, try_data
);
2670 frame
->pc
= try_data
->catch_start
;
2672 if (try_data
->use_register
)
2674 if (try_data
->register_number
< frame
->n_registers
) {
2675 frame
->registers
[try_data
->register_number
] = val
;
2677 SWFDEC_ERROR ("cannot set Error to register %u: not enough registers",
2678 try_data
->register_number
);
2683 swfdec_as_object_set_variable (try_data
->scope_object
,
2684 swfdec_as_context_get_string (cx
, try_data
->variable_name
), &val
);
2689 swfdec_action_try_data_free (try_data
);
2694 swfdec_action_try (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2699 gboolean use_finally
, use_catch
;
2702 SWFDEC_ERROR ("With action requires a length of at least 8, but got %u",
2707 try_data
= g_malloc0 (sizeof (TryData
));
2709 swfdec_bits_init_data (&bits
, data
, len
);
2711 swfdec_bits_getbits (&bits
, 5); // reserved
2712 try_data
->use_register
= swfdec_bits_getbit (&bits
);
2713 use_finally
= swfdec_bits_getbit (&bits
);
2714 use_catch
= swfdec_bits_getbit (&bits
);
2716 try_size
= swfdec_bits_get_u16 (&bits
);
2717 try_data
->catch_size
= swfdec_bits_get_u16 (&bits
);
2718 try_data
->finally_size
= swfdec_bits_get_u16 (&bits
);
2720 try_data
->catch_start
= data
+ len
+ try_size
;
2722 try_data
->finally_start
= data
+ len
+ try_size
+
2723 (use_catch
? try_data
->catch_size
: 0);
2726 if (try_data
->use_register
) {
2727 try_data
->register_number
= swfdec_bits_get_u8 (&bits
);
2729 try_data
->variable_name
=
2730 swfdec_bits_get_string (&bits
, cx
->version
);
2733 if (swfdec_bits_left (&bits
)) {
2734 SWFDEC_WARNING ("leftover bytes in Try action");
2737 if (try_data
->catch_start
|| try_data
->finally_start
) {
2738 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ try_size
,
2739 swfdec_action_try_end_try
, try_data
);
2741 SWFDEC_WARNING ("Try with neither catch nor finally block");
2742 swfdec_action_try_data_free (try_data
);
2747 swfdec_action_pop_with (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, gpointer with_object
)
2749 g_assert (frame
->scope_chain
->data
== with_object
);
2750 frame
->scope_chain
= g_slist_delete_link (frame
->scope_chain
, frame
->scope_chain
);
2754 swfdec_action_with (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2756 SwfdecAsObject
*object
;
2760 SWFDEC_ERROR ("With action requires a length of 2, but got %u", len
);
2761 swfdec_as_stack_pop (cx
);
2764 offset
= data
[0] | (data
[1] << 8);
2765 object
= swfdec_as_value_to_object (cx
, swfdec_as_stack_peek (cx
, 1));
2766 if (object
== NULL
) {
2767 SWFDEC_INFO ("With called without an object, skipping");
2768 cx
->frame
->pc
= (guint8
*) data
+ len
+ offset
;
2770 cx
->frame
->scope_chain
= g_slist_prepend (cx
->frame
->scope_chain
, object
);
2771 swfdec_as_frame_push_block (cx
->frame
, data
+ len
, data
+ len
+ offset
,
2772 swfdec_action_pop_with
, object
);
2774 swfdec_as_stack_pop (cx
);
2778 swfdec_action_remove_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2780 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
2781 if (target
== NULL
) {
2782 SWFDEC_FIXME ("target is not a movie in RemoveSprite");
2783 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2784 SWFDEC_INFO ("tried using RemoveSprite in a non-SwfdecPlayer context");
2786 SwfdecMovie
*movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2787 swfdec_as_stack_peek (cx
, 1));
2788 if (movie
&& swfdec_depth_classify (movie
->depth
) == SWFDEC_DEPTH_CLASS_DYNAMIC
) {
2789 SWFDEC_LOG ("removing clip %s", movie
->name
);
2790 swfdec_movie_remove (movie
);
2792 SWFDEC_INFO ("cannot remove movie");
2795 swfdec_as_stack_pop (cx
);
2799 swfdec_action_clone_sprite (SwfdecAsContext
*cx
, guint action
, const guint8
*data
, guint len
)
2801 SwfdecMovie
*target
= swfdec_as_frame_get_target (cx
->frame
);
2802 SwfdecMovie
*movie
, *new_movie
;
2803 const char *new_name
;
2806 depth
= swfdec_as_value_to_integer (cx
, swfdec_as_stack_peek (cx
, 1)) - 16384;
2807 new_name
= swfdec_as_value_to_string (cx
, swfdec_as_stack_peek (cx
, 2));
2808 if (target
== NULL
) {
2809 SWFDEC_FIXME ("target is not a movie in CloneSprite");
2810 } else if (!SWFDEC_IS_PLAYER (cx
)) {
2811 SWFDEC_INFO ("tried using CloneSprite in a non-SwfdecPlayer context");
2813 movie
= swfdec_player_get_movie_from_value (SWFDEC_PLAYER (cx
),
2814 swfdec_as_stack_peek (cx
, 3));
2815 if (movie
== NULL
) {
2816 SWFDEC_ERROR ("Object is not an SwfdecMovie object");
2817 swfdec_as_stack_pop_n (cx
, 3);
2820 new_movie
= swfdec_movie_duplicate (movie
, new_name
, depth
);
2822 SWFDEC_LOG ("duplicated %s as %s to depth %u", movie
->name
, new_movie
->name
, new_movie
->depth
);
2825 swfdec_as_stack_pop_n (cx
, 3);
2828 /*** BIG FUNCTION TABLE ***/
2830 const SwfdecActionSpec swfdec_as_actions
[256] = {
2832 [SWFDEC_AS_ACTION_END
] = { "End", 0, 0, swfdec_action_end
, 1 },
2833 [SWFDEC_AS_ACTION_NEXT_FRAME
] = { "NextFrame", 0, 0, swfdec_action_next_frame
, 1 },
2834 [SWFDEC_AS_ACTION_PREVIOUS_FRAME
] = { "PreviousFrame", 0, 0, swfdec_action_previous_frame
, 1 },
2835 [SWFDEC_AS_ACTION_PLAY
] = { "Play", 0, 0, swfdec_action_play
, 1 },
2836 [SWFDEC_AS_ACTION_STOP
] = { "Stop", 0, 0, swfdec_action_stop
, 1 },
2837 [SWFDEC_AS_ACTION_TOGGLE_QUALITY
] = { "ToggleQuality", -1, -1, NULL
, 1 },
2839 [SWFDEC_AS_ACTION_STOP_SOUNDS
] = { "StopSounds", 0, 0, swfdec_action_stop_sounds
, 2 },
2841 [SWFDEC_AS_ACTION_ADD
] = { "Add", 2, 1, swfdec_action_binary
, 4 },
2842 [SWFDEC_AS_ACTION_SUBTRACT
] = { "Subtract", 2, 1, swfdec_action_binary
, 4 },
2843 [SWFDEC_AS_ACTION_MULTIPLY
] = { "Multiply", 2, 1, swfdec_action_binary
, 4 },
2844 [SWFDEC_AS_ACTION_DIVIDE
] = { "Divide", 2, 1, swfdec_action_binary
, 4 },
2845 [SWFDEC_AS_ACTION_EQUALS
] = { "Equals", 2, 1, swfdec_action_old_compare
, 4 },
2846 [SWFDEC_AS_ACTION_LESS
] = { "Less", 2, 1, swfdec_action_old_compare
, 4 },
2847 [SWFDEC_AS_ACTION_AND
] = { "And", 2, 1, swfdec_action_logical
, 4 },
2848 [SWFDEC_AS_ACTION_OR
] = { "Or", 2, 1, swfdec_action_logical
, 4 },
2849 [SWFDEC_AS_ACTION_NOT
] = { "Not", 1, 1, swfdec_action_not
, 4 },
2850 [SWFDEC_AS_ACTION_STRING_EQUALS
] = { "StringEquals", 2, 1, swfdec_action_string_compare
, 4 },
2851 [SWFDEC_AS_ACTION_STRING_LENGTH
] = { "StringLength", 1, 1, swfdec_action_string_length
, 4 },
2852 [SWFDEC_AS_ACTION_STRING_EXTRACT
] = { "StringExtract", 3, 1, swfdec_action_string_extract
, 4 },
2853 [SWFDEC_AS_ACTION_POP
] = { "Pop", 1, 0, swfdec_action_pop
, 4 },
2854 [SWFDEC_AS_ACTION_TO_INTEGER
] = { "ToInteger", 1, 1, swfdec_action_to_integer
, 4 },
2855 [SWFDEC_AS_ACTION_GET_VARIABLE
] = { "GetVariable", 1, 1, swfdec_action_get_variable
, 4 },
2856 [SWFDEC_AS_ACTION_SET_VARIABLE
] = { "SetVariable", 2, 0, swfdec_action_set_variable
, 4 },
2858 [SWFDEC_AS_ACTION_SET_TARGET2
] = { "SetTarget2", 1, 0, swfdec_action_set_target2
, 3 },
2860 [SWFDEC_AS_ACTION_STRING_ADD
] = { "StringAdd", 2, 1, swfdec_action_string_add
, 4 },
2861 [SWFDEC_AS_ACTION_GET_PROPERTY
] = { "GetProperty", 2, 1, swfdec_action_get_property
, 4 },
2862 [SWFDEC_AS_ACTION_SET_PROPERTY
] = { "SetProperty", 3, 0, swfdec_action_set_property
, 4 },
2863 [SWFDEC_AS_ACTION_CLONE_SPRITE
] = { "CloneSprite", 3, 0, swfdec_action_clone_sprite
, 4 },
2864 [SWFDEC_AS_ACTION_REMOVE_SPRITE
] = { "RemoveSprite", 1, 0, swfdec_action_remove_sprite
, 4 },
2865 [SWFDEC_AS_ACTION_TRACE
] = { "Trace", 1, 0, swfdec_action_trace
, 4 },
2866 [SWFDEC_AS_ACTION_START_DRAG
] = { "StartDrag", -1, 0, swfdec_action_start_drag
, 4 },
2867 [SWFDEC_AS_ACTION_END_DRAG
] = { "EndDrag", 0, 0, swfdec_action_end_drag
, 4 },
2868 [SWFDEC_AS_ACTION_STRING_LESS
] = { "StringLess", 2, 1, swfdec_action_string_compare
, 4 },
2870 [SWFDEC_AS_ACTION_THROW
] = { "Throw", 1, 0, swfdec_action_throw
, 7 },
2871 [SWFDEC_AS_ACTION_CAST
] = { "Cast", 2, 1, swfdec_action_cast
, 7 },
2872 [SWFDEC_AS_ACTION_IMPLEMENTS
] = { "Implements", -1, 0, swfdec_action_implements
, 7 },
2874 [SWFDEC_AS_ACTION_RANDOM
] = { "RandomNumber", 1, 1, swfdec_action_random_number
, 4 },
2875 [SWFDEC_AS_ACTION_MB_STRING_LENGTH
] = { "MBStringLength", 1, 1, swfdec_action_string_length
, 4 },
2876 [SWFDEC_AS_ACTION_CHAR_TO_ASCII
] = { "CharToAscii", 1, 1, swfdec_action_char_to_ascii
, 4 },
2877 [SWFDEC_AS_ACTION_ASCII_TO_CHAR
] = { "AsciiToChar", 1, 1, swfdec_action_ascii_to_char
, 4 },
2878 [SWFDEC_AS_ACTION_GET_TIME
] = { "GetTime", 0, 1, swfdec_action_get_time
, 4 },
2879 [SWFDEC_AS_ACTION_MB_STRING_EXTRACT
] = { "MBStringExtract", 3, 1, swfdec_action_string_extract
, 4 },
2880 [SWFDEC_AS_ACTION_MB_CHAR_TO_ASCII
] = { "MBCharToAscii", 1, 1, swfdec_action_char_to_ascii
, 4 },
2881 [SWFDEC_AS_ACTION_MB_ASCII_TO_CHAR
] = { "MBAsciiToChar", 1, 1, swfdec_action_ascii_to_char
, 4 },
2883 [SWFDEC_AS_ACTION_DELETE
] = { "Delete", 2, 1, swfdec_action_delete
, 5 },
2884 [SWFDEC_AS_ACTION_DELETE2
] = { "Delete2", 1, 1, swfdec_action_delete2
, 5 },
2885 [SWFDEC_AS_ACTION_DEFINE_LOCAL
] = { "DefineLocal", 2, 0, swfdec_action_define_local
, 5 },
2886 [SWFDEC_AS_ACTION_CALL_FUNCTION
] = { "CallFunction", -1, 1, swfdec_action_call_function
, 5 },
2887 [SWFDEC_AS_ACTION_RETURN
] = { "Return", 1, 0, swfdec_action_return
, 5 },
2888 [SWFDEC_AS_ACTION_MODULO
] = { "Modulo", 2, 1, swfdec_action_modulo
, 5 },
2889 [SWFDEC_AS_ACTION_NEW_OBJECT
] = { "NewObject", -1, 1, swfdec_action_new_object
, 5 },
2890 [SWFDEC_AS_ACTION_DEFINE_LOCAL2
] = { "DefineLocal2", 1, 0, swfdec_action_define_local2
, 5 },
2891 [SWFDEC_AS_ACTION_INIT_ARRAY
] = { "InitArray", -1, 1, swfdec_action_init_array
, 5 },
2892 [SWFDEC_AS_ACTION_INIT_OBJECT
] = { "InitObject", -1, 1, swfdec_action_init_object
, 5 },
2893 [SWFDEC_AS_ACTION_TYPE_OF
] = { "TypeOf", 1, 1, swfdec_action_type_of
, 5 },
2894 [SWFDEC_AS_ACTION_TARGET_PATH
] = { "TargetPath", 1, 1, swfdec_action_target_path
, 5 },
2895 [SWFDEC_AS_ACTION_ENUMERATE
] = { "Enumerate", 1, -1, swfdec_action_enumerate
, 5 },
2896 [SWFDEC_AS_ACTION_ADD2
] = { "Add2", 2, 1, swfdec_action_add2
, 5 },
2897 [SWFDEC_AS_ACTION_LESS2
] = { "Less2", 2, 1, swfdec_action_new_comparison
, 5 },
2898 [SWFDEC_AS_ACTION_EQUALS2
] = { "Equals2", 2, 1, swfdec_action_equals2
, 5 },
2899 [SWFDEC_AS_ACTION_TO_NUMBER
] = { "ToNumber", 1, 1, swfdec_action_to_number
, 5 },
2900 [SWFDEC_AS_ACTION_TO_STRING
] = { "ToString", 1, 1, swfdec_action_to_string
, 5 },
2901 [SWFDEC_AS_ACTION_PUSH_DUPLICATE
] = { "PushDuplicate", 1, 2, swfdec_action_push_duplicate
, 5 },
2902 [SWFDEC_AS_ACTION_SWAP
] = { "Swap", 2, 2, swfdec_action_swap
, 5 },
2904 [SWFDEC_AS_ACTION_GET_MEMBER
] = { "GetMember", 2, 1, swfdec_action_get_member
, 4 },
2905 [SWFDEC_AS_ACTION_SET_MEMBER
] = { "SetMember", 3, 0, swfdec_action_set_member
, 4 },
2907 [SWFDEC_AS_ACTION_INCREMENT
] = { "Increment", 1, 1, swfdec_action_increment
, 5 },
2908 [SWFDEC_AS_ACTION_DECREMENT
] = { "Decrement", 1, 1, swfdec_action_decrement
, 5 },
2909 [SWFDEC_AS_ACTION_CALL_METHOD
] = { "CallMethod", -1, 1, swfdec_action_call_method
, 5 },
2910 [SWFDEC_AS_ACTION_NEW_METHOD
] = { "NewMethod", -1, 1, swfdec_action_new_method
, 5 },
2912 [SWFDEC_AS_ACTION_INSTANCE_OF
] = { "InstanceOf", 2, 1, swfdec_action_instance_of
, 6 },
2913 [SWFDEC_AS_ACTION_ENUMERATE2
] = { "Enumerate2", 1, -1, swfdec_action_enumerate2
, 6 },
2914 [SWFDEC_AS_ACTION_BREAKPOINT
] = { "Breakpoint", -1, -1, NULL
, 6 },
2916 [SWFDEC_AS_ACTION_BIT_AND
] = { "BitAnd", 2, 1, swfdec_action_bitwise
, 5 },
2917 [SWFDEC_AS_ACTION_BIT_OR
] = { "BitOr", 2, 1, swfdec_action_bitwise
, 5 },
2918 [SWFDEC_AS_ACTION_BIT_XOR
] = { "BitXor", 2, 1, swfdec_action_bitwise
, 5 },
2919 [SWFDEC_AS_ACTION_BIT_LSHIFT
] = { "BitLShift", 2, 1, swfdec_action_shift
, 5 },
2920 [SWFDEC_AS_ACTION_BIT_RSHIFT
] = { "BitRShift", 2, 1, swfdec_action_shift
, 5 },
2921 [SWFDEC_AS_ACTION_BIT_URSHIFT
] = { "BitURShift", 2, 1, swfdec_action_shift
, 5 },
2923 [SWFDEC_AS_ACTION_STRICT_EQUALS
] = { "StrictEquals", 2, 1, swfdec_action_strict_equals
, 6 },
2924 [SWFDEC_AS_ACTION_GREATER
] = { "Greater", 2, 1, swfdec_action_new_comparison
, 6 },
2925 [SWFDEC_AS_ACTION_STRING_GREATER
] = { "StringGreater", 2, 1, swfdec_action_string_compare
, 6 },
2927 [SWFDEC_AS_ACTION_EXTENDS
] = { "Extends", 2, 0, swfdec_action_extends
, 7 },
2929 [SWFDEC_AS_ACTION_GOTO_FRAME
] = { "GotoFrame", 0, 0, swfdec_action_goto_frame
, 1 },
2930 [SWFDEC_AS_ACTION_GET_URL
] = { "GetURL", 0, 0, swfdec_action_get_url
, 1 },
2932 [SWFDEC_AS_ACTION_STORE_REGISTER
] = { "StoreRegister", 1, 1, swfdec_action_store_register
, 5 },
2933 [SWFDEC_AS_ACTION_CONSTANT_POOL
] = { "ConstantPool", 0, 0, swfdec_action_constant_pool
, 5 },
2934 [SWFDEC_AS_ACTION_STRICT_MODE
] = { "StrictMode", -1, -1, NULL
, 5 },
2936 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME
] = { "WaitForFrame", 0, 0, swfdec_action_wait_for_frame
, 1 },
2937 [SWFDEC_AS_ACTION_SET_TARGET
] = { "SetTarget", 0, 0, swfdec_action_set_target
, 1 },
2939 [SWFDEC_AS_ACTION_GOTO_LABEL
] = { "GotoLabel", 0, 0, swfdec_action_goto_label
, 3 },
2941 [SWFDEC_AS_ACTION_WAIT_FOR_FRAME2
] = { "WaitForFrame2", 1, 0, swfdec_action_wait_for_frame2
, 4 },
2943 [SWFDEC_AS_ACTION_DEFINE_FUNCTION2
] = { "DefineFunction2", 0, -1, swfdec_action_define_function
, 7 },
2944 [SWFDEC_AS_ACTION_TRY
] = { "Try", 0, 0, swfdec_action_try
, 7 },
2946 [SWFDEC_AS_ACTION_WITH
] = { "With", 1, 0, swfdec_action_with
, 5 },
2948 [SWFDEC_AS_ACTION_PUSH
] = { "Push", 0, -1, swfdec_action_push
, 4 },
2949 [SWFDEC_AS_ACTION_JUMP
] = { "Jump", 0, 0, swfdec_action_jump
, 4 },
2950 [SWFDEC_AS_ACTION_GET_URL2
] = { "GetURL2", 2, 0, swfdec_action_get_url2
, 4 },
2952 [SWFDEC_AS_ACTION_DEFINE_FUNCTION
] = { "DefineFunction", 0, -1, swfdec_action_define_function
, 5 },
2954 [SWFDEC_AS_ACTION_IF
] = { "If", 1, 0, swfdec_action_if
, 4 },
2955 [SWFDEC_AS_ACTION_CALL
] = { "Call", -1, -1, NULL
, 4 },
2956 [SWFDEC_AS_ACTION_GOTO_FRAME2
] = { "GotoFrame2", 1, 0, swfdec_action_goto_frame2
, 4 }