fix jsut committed crasher by rewriting startDrag action
[swfdec.git] / libswfdec / swfdec_script.c
blob0465d9d10a90fea1e6088fb311e0b280df1da338
1 /* Swfdec
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.
8 *
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
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
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"
30 /**
31 * SwfdecScript:
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 */
51 SwfdecConstantPool *
52 swfdec_constant_pool_new_from_action (const guint8 *data, guint len, guint version)
54 guint i, n;
55 SwfdecBits bits;
56 SwfdecConstantPool *pool;
58 swfdec_bits_init_data (&bits, data, len);
60 n = swfdec_bits_get_u16 (&bits);
61 if (n == 0)
62 return NULL;
64 pool = g_malloc0 (sizeof (SwfdecConstantPool) + (n - 1) * sizeof (char *));
65 pool->n_strings = n;
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);
71 return NULL;
74 if (swfdec_bits_left (&bits)) {
75 SWFDEC_WARNING ("constant pool didn't consume whole buffer (%u bytes leftover)", swfdec_bits_left (&bits) / 8);
77 return pool;
80 void
81 swfdec_constant_pool_attach_to_context (SwfdecConstantPool *pool, SwfdecAsContext *context)
83 guint i;
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]);
95 guint
96 swfdec_constant_pool_size (SwfdecConstantPool *pool)
98 return pool->n_strings;
101 const char *
102 swfdec_constant_pool_get (SwfdecConstantPool *pool, guint i)
104 g_assert (i < pool->n_strings);
105 return pool->strings[i];
108 void
109 swfdec_constant_pool_free (SwfdecConstantPool *pool)
111 if (pool->context == NULL) {
112 guint i;
113 for (i = 0; i < pool->n_strings; i++) {
114 g_free (pool->strings[i]);
117 g_free (pool);
120 /*** SUPPORT FUNCTIONS ***/
122 char *
123 swfdec_script_print_action (guint action, const guint8 *data, guint len)
125 const SwfdecActionSpec *spec = swfdec_as_actions + action;
127 if (action & 0x80) {
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);
135 } else {
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);
144 static gboolean
145 swfdec_script_foreach_internal (SwfdecBits *bits, SwfdecScriptForeachFunc func, gpointer user_data)
147 guint action, len;
148 const guint8 *data;
149 gconstpointer bytecode;
151 bytecode = bits->ptr;
152 while (swfdec_bits_left (bits) && (action = swfdec_bits_get_u8 (bits))) {
153 if (action & 0x80) {
154 len = swfdec_bits_get_u16 (bits);
155 data = bits->ptr;
156 } else {
157 len = 0;
158 data = NULL;
160 if (swfdec_bits_skip_bytes (bits, len) != len) {
161 SWFDEC_ERROR ("script too short");
162 return FALSE;
164 if (!func (bytecode, action, data, len, user_data))
165 return FALSE;
166 bytecode = bits->ptr;
168 return TRUE;
171 /*** PUBLIC API ***/
173 gboolean
174 swfdec_script_foreach (SwfdecScript *script, SwfdecScriptForeachFunc func, gpointer user_data)
176 SwfdecBits bits;
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);
185 static gboolean
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",
195 script->version);
197 /* we might want to do stuff here for certain actions */
198 #if 0
200 char *foo = swfdec_script_print_action (action, data, len);
201 if (foo == NULL)
202 return FALSE;
203 g_print ("%s\n", foo);
205 #endif
206 return TRUE;
210 * swfdec_script_new:
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.
220 SwfdecScript *
221 swfdec_script_new (SwfdecBuffer *buffer, const char *name, guint version)
223 SwfdecBits bits;
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);
231 return script;
234 SwfdecScript *
235 swfdec_script_new_from_bits (SwfdecBits *bits, const char *name, guint version)
237 SwfdecScript *script;
238 SwfdecBits org;
239 guint len;
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);
245 return NULL;
248 org = *bits;
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);
262 return NULL;
264 len -= swfdec_bits_left (bits) / 8;
265 if (len == 0) {
266 script->buffer = swfdec_buffer_new ();
267 } else {
268 script->buffer = swfdec_bits_get_buffer (&org, len);
270 return script;
273 SwfdecScript *
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);
279 script->refcount++;
280 return script;
283 void
284 swfdec_script_unref (SwfdecScript *script)
286 guint i;
288 g_return_if_fail (script != NULL);
289 g_return_if_fail (script->refcount > 0);
291 script->refcount--;
292 if (script->refcount > 0)
293 return;
295 if (script->buffer)
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);
304 g_free (script);
307 /*** UTILITY FUNCTIONS ***/
309 const char *
310 swfdec_action_get_name (guint action)
312 g_return_val_if_fail (action < 256, NULL);
314 return swfdec_as_actions[action].name;
317 guint
318 swfdec_action_get_from_name (const char *name)
320 guint i;
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))
326 return i;
328 return 0;