2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
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_script.h"
25 #include "swfdec_script_internal.h"
26 #include "swfdec_as_context.h"
27 #include "swfdec_as_interpret.h"
28 #include "swfdec_debug.h"
33 * This is the object used for code to be executed by Swfdec. Scripts are
34 * independant from the #SwfdecAsContext they are executed in, so you can
35 * execute the same script in multiple contexts.
38 /* Define this to get SWFDEC_WARN'd about missing properties of objects.
39 * This can be useful to find out about unimplemented native properties,
40 * but usually just causes a lot of spam. */
41 //#define SWFDEC_WARN_MISSING_PROPERTIES
43 /*** CONSTANT POOLS ***/
45 struct _SwfdecConstantPool
{
46 SwfdecAsContext
* context
; /* context we are attached to or NULL */
47 guint n_strings
; /* number of strings */
48 char * strings
[1]; /* n_strings strings */
52 swfdec_constant_pool_new_from_action (const guint8
*data
, guint len
, guint version
)
56 SwfdecConstantPool
*pool
;
58 swfdec_bits_init_data (&bits
, data
, len
);
60 n
= swfdec_bits_get_u16 (&bits
);
64 pool
= g_malloc0 (sizeof (SwfdecConstantPool
) + (n
- 1) * sizeof (char *));
66 for (i
= 0; i
< n
; i
++) {
67 pool
->strings
[i
] = swfdec_bits_get_string_with_version (&bits
, version
);
68 if (pool
->strings
[i
] == NULL
) {
69 SWFDEC_ERROR ("not enough strings available");
70 swfdec_constant_pool_free (pool
);
74 if (swfdec_bits_left (&bits
)) {
75 SWFDEC_WARNING ("constant pool didn't consume whole buffer (%u bytes leftover)", swfdec_bits_left (&bits
) / 8);
81 swfdec_constant_pool_attach_to_context (SwfdecConstantPool
*pool
, SwfdecAsContext
*context
)
85 g_return_if_fail (pool
!= NULL
);
86 g_return_if_fail (pool
->context
== NULL
);
87 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context
));
89 pool
->context
= context
;
90 for (i
= 0; i
< pool
->n_strings
; i
++) {
91 pool
->strings
[i
] = (char *) swfdec_as_context_give_string (context
, pool
->strings
[i
]);
96 swfdec_constant_pool_size (SwfdecConstantPool
*pool
)
98 return pool
->n_strings
;
102 swfdec_constant_pool_get (SwfdecConstantPool
*pool
, guint i
)
104 g_assert (i
< pool
->n_strings
);
105 return pool
->strings
[i
];
109 swfdec_constant_pool_free (SwfdecConstantPool
*pool
)
111 if (pool
->context
== NULL
) {
113 for (i
= 0; i
< pool
->n_strings
; i
++) {
114 g_free (pool
->strings
[i
]);
120 /*** SUPPORT FUNCTIONS ***/
123 swfdec_script_print_action (guint action
, const guint8
*data
, guint len
)
125 const SwfdecActionSpec
*spec
= swfdec_as_actions
+ action
;
128 if (spec
->print
== NULL
) {
129 SWFDEC_ERROR ("action %u 0x%02X %s has no print statement",
130 action
, action
, spec
->name
? spec
->name
: "Unknown");
131 return g_strdup_printf ("erroneous action %s",
132 spec
->name
? spec
->name
: "Unknown");
134 return spec
->print (action
, data
, len
);
136 if (spec
->name
== NULL
) {
137 SWFDEC_ERROR ("action %u is unknown", action
);
138 return g_strdup_printf ("unknown Action 0x%02X", action
);
140 return g_strdup (spec
->name
);
145 swfdec_script_foreach_internal (SwfdecBits
*bits
, SwfdecScriptForeachFunc func
, gpointer user_data
)
149 gconstpointer bytecode
;
151 bytecode
= bits
->ptr
;
152 while (swfdec_bits_left (bits
) && (action
= swfdec_bits_get_u8 (bits
))) {
154 len
= swfdec_bits_get_u16 (bits
);
160 if (swfdec_bits_skip_bytes (bits
, len
) != len
) {
161 SWFDEC_ERROR ("script too short");
164 if (!func (bytecode
, action
, data
, len
, user_data
))
166 bytecode
= bits
->ptr
;
174 swfdec_script_foreach (SwfdecScript
*script
, SwfdecScriptForeachFunc func
, gpointer user_data
)
178 g_return_val_if_fail (script
!= NULL
, FALSE
);
179 g_return_val_if_fail (func
!= NULL
, FALSE
);
181 swfdec_bits_init (&bits
, script
->buffer
);
182 return swfdec_script_foreach_internal (&bits
, func
, user_data
);
186 validate_action (gconstpointer bytecode
, guint action
, const guint8
*data
, guint len
, gpointer scriptp
)
188 SwfdecScript
*script
= scriptp
;
189 int version
= SWFDEC_AS_EXTRACT_SCRIPT_VERSION (script
->version
);
191 /* warn if there's no function to execute this opcode */
192 if (swfdec_as_actions
[action
].exec
[version
] == NULL
) {
193 SWFDEC_ERROR ("no function for %3u 0x%02X %s in v%u", action
, action
,
194 swfdec_as_actions
[action
].name
? swfdec_as_actions
[action
].name
: "Unknown",
197 /* we might want to do stuff here for certain actions */
200 char *foo
= swfdec_script_print_action (action
, data
, len
);
203 g_print ("%s\n", foo
);
211 * @buffer: the #SwfdecBuffer containing the script. This function will take
212 * ownership of the passed in buffer.
213 * @name: name of the script for debugging purposes
214 * @version: Actionscript version to use in this script
216 * Creates a new script for the actionscript provided in @buffer.
218 * Returns: a new #SwfdecScript for executing the script i @buffer.
221 swfdec_script_new (SwfdecBuffer
*buffer
, const char *name
, guint version
)
224 SwfdecScript
*script
;
226 g_return_val_if_fail (buffer
!= NULL
, NULL
);
228 swfdec_bits_init (&bits
, buffer
);
229 script
= swfdec_script_new_from_bits (&bits
, name
, version
);
230 swfdec_buffer_unref (buffer
);
235 swfdec_script_new_from_bits (SwfdecBits
*bits
, const char *name
, guint version
)
237 SwfdecScript
*script
;
241 g_return_val_if_fail (bits
!= NULL
, NULL
);
243 if (version
< SWFDEC_AS_MIN_SCRIPT_VERSION
) {
244 SWFDEC_ERROR ("swfdec version %u doesn't support scripts", version
);
249 len
= swfdec_bits_left (bits
) / 8;
250 script
= g_new0 (SwfdecScript
, 1);
251 script
->refcount
= 1;
252 script
->name
= g_strdup (name
? name
: "Unnamed script");
253 script
->version
= version
;
254 /* by default, a function has 4 registers */
255 script
->n_registers
= 5;
256 /* These flags are the default arguments used by scripts read from a file.
257 * DefineFunction and friends override this */
258 script
->flags
= SWFDEC_SCRIPT_SUPPRESS_ARGS
;
260 if (!swfdec_script_foreach_internal (bits
, validate_action
, script
)) {
261 swfdec_script_unref (script
);
264 len
-= swfdec_bits_left (bits
) / 8;
266 script
->buffer
= swfdec_buffer_new ();
268 script
->buffer
= swfdec_bits_get_buffer (&org
, len
);
274 swfdec_script_ref (SwfdecScript
*script
)
276 g_return_val_if_fail (script
!= NULL
, NULL
);
277 g_return_val_if_fail (script
->refcount
> 0, NULL
);
284 swfdec_script_unref (SwfdecScript
*script
)
288 g_return_if_fail (script
!= NULL
);
289 g_return_if_fail (script
->refcount
> 0);
292 if (script
->refcount
> 0)
296 swfdec_buffer_unref (script
->buffer
);
297 if (script
->constant_pool
)
298 swfdec_buffer_unref (script
->constant_pool
);
299 g_free (script
->name
);
300 for (i
= 0; i
< script
->n_arguments
; i
++) {
301 g_free (script
->arguments
[i
].name
);
303 g_free (script
->arguments
);
307 /*** UTILITY FUNCTIONS ***/
310 swfdec_action_get_name (guint action
)
312 g_return_val_if_fail (action
< 256, NULL
);
314 return swfdec_as_actions
[action
].name
;
318 swfdec_action_get_from_name (const char *name
)
322 g_return_val_if_fail (name
!= NULL
, 0);
324 for (i
= 0; i
< 256; i
++) {
325 if (swfdec_as_actions
[i
].name
&& g_str_equal (name
, swfdec_as_actions
[i
].name
))